初始化

This commit is contained in:
ouyang 2017-08-15 15:04:48 +08:00
parent f1de8d5d3e
commit 9412cc7505
3464 changed files with 236938 additions and 0 deletions

View File

14
BageView/build.gradle Normal file
View File

@ -0,0 +1,14 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
}
}
// gradle uploadArchives
//apply from: 'https://raw.githubusercontent.com/bingoogolapple/PublishAar/master/central-publish.gradle'

View File

@ -0,0 +1,3 @@
PUBLISH_AAR_ARTIFACT_ID=bga-badgeview
PUBLISH_AAR_DESCRIPTION=Android BadgeView Library
PUBLISH_AAR_GITHUB_REPOSITORIES_NAME=BGABadgeView-Android

View File

@ -0,0 +1,3 @@
<manifest package="cn.bingoogolapple.badgeview"/>
<!--
ss-->

View File

@ -0,0 +1,98 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/7 14:07
* 描述:
*/
public class BGABadgeFrameLayout extends FrameLayout implements BGABadgeable {
private BGABadgeViewHelper mBadgeViewHeler;
public BGABadgeFrameLayout(Context context) {
this(context, null);
}
public BGABadgeFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BGABadgeFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBadgeViewHeler = new BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightCenter);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mBadgeViewHeler.onTouchEvent(event);
}
@Override
public boolean callSuperOnTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
mBadgeViewHeler.drawBadge(canvas);
}
@Override
public void showCirclePointBadge() {
mBadgeViewHeler.showCirclePointBadge();
}
@Override
public void showTextBadge(String badgeText) {
mBadgeViewHeler.showTextBadge(badgeText);
}
@Override
public void hiddenBadge() {
mBadgeViewHeler.hiddenBadge();
}
@Override
public void showDrawableBadge(Bitmap bitmap) {
mBadgeViewHeler.showDrawable(bitmap);
}
@Override
public void setDragDismissDelegage(BGADragDismissDelegate delegate) {
mBadgeViewHeler.setDragDismissDelegage(delegate);
}
@Override
public boolean isShowBadge() {
return mBadgeViewHeler.isShowBadge();
}
@Override
public BGABadgeViewHelper getBadgeViewHelper() {
return mBadgeViewHeler;
}
}

View File

@ -0,0 +1,97 @@
/**
* Copyright 2015 bingoogolapple
*
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/6 下午3:04
* 描述:
*/
public class BGABadgeImageView extends ImageView implements BGABadgeable {
private BGABadgeViewHelper mBadgeViewHeler;
public BGABadgeImageView(Context context) {
this(context, null);
}
public BGABadgeImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BGABadgeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBadgeViewHeler = new BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightTop);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mBadgeViewHeler.onTouchEvent(event);
}
@Override
public boolean callSuperOnTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mBadgeViewHeler.drawBadge(canvas);
}
@Override
public void showCirclePointBadge() {
mBadgeViewHeler.showCirclePointBadge();
}
@Override
public void showTextBadge(String badgeText) {
mBadgeViewHeler.showTextBadge(badgeText);
}
@Override
public void hiddenBadge() {
mBadgeViewHeler.hiddenBadge();
}
@Override
public void showDrawableBadge(Bitmap bitmap) {
mBadgeViewHeler.showDrawable(bitmap);
}
@Override
public void setDragDismissDelegage(BGADragDismissDelegate delegate) {
mBadgeViewHeler.setDragDismissDelegage(delegate);
}
@Override
public boolean isShowBadge() {
return mBadgeViewHeler.isShowBadge();
}
@Override
public BGABadgeViewHelper getBadgeViewHelper() {
return mBadgeViewHeler;
}
}

View File

@ -0,0 +1,93 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/7 14:07
* 描述:
*/
public class BGABadgeLinearLayout extends LinearLayout implements BGABadgeable {
private BGABadgeViewHelper mBadgeViewHeler;
public BGABadgeLinearLayout(Context context) {
this(context, null);
}
public BGABadgeLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mBadgeViewHeler = new BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightCenter);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mBadgeViewHeler.onTouchEvent(event);
}
@Override
public boolean callSuperOnTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
mBadgeViewHeler.drawBadge(canvas);
}
@Override
public void showCirclePointBadge() {
mBadgeViewHeler.showCirclePointBadge();
}
@Override
public void showTextBadge(String badgeText) {
mBadgeViewHeler.showTextBadge(badgeText);
}
@Override
public void hiddenBadge() {
mBadgeViewHeler.hiddenBadge();
}
@Override
public void showDrawableBadge(Bitmap bitmap) {
mBadgeViewHeler.showDrawable(bitmap);
}
@Override
public void setDragDismissDelegage(BGADragDismissDelegate delegate) {
mBadgeViewHeler.setDragDismissDelegage(delegate);
}
@Override
public boolean isShowBadge() {
return mBadgeViewHeler.isShowBadge();
}
@Override
public BGABadgeViewHelper getBadgeViewHelper() {
return mBadgeViewHeler;
}
}

View File

@ -0,0 +1,97 @@
/**
* Copyright 2015 bingoogolapple
*
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RadioButton;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/6 下午3:04
* 描述:
*/
public class BGABadgeRadioButton extends RadioButton implements BGABadgeable {
private BGABadgeViewHelper mBadgeViewHeler;
public BGABadgeRadioButton(Context context) {
this(context, null);
}
public BGABadgeRadioButton(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.radioButtonStyle);
}
public BGABadgeRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBadgeViewHeler = new BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightTop);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mBadgeViewHeler.onTouchEvent(event);
}
@Override
public boolean callSuperOnTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mBadgeViewHeler.drawBadge(canvas);
}
@Override
public void showCirclePointBadge() {
mBadgeViewHeler.showCirclePointBadge();
}
@Override
public void showTextBadge(String badgeText) {
mBadgeViewHeler.showTextBadge(badgeText);
}
@Override
public void hiddenBadge() {
mBadgeViewHeler.hiddenBadge();
}
@Override
public void showDrawableBadge(Bitmap bitmap) {
mBadgeViewHeler.showDrawable(bitmap);
}
@Override
public void setDragDismissDelegage(BGADragDismissDelegate delegate) {
mBadgeViewHeler.setDragDismissDelegage(delegate);
}
@Override
public boolean isShowBadge() {
return mBadgeViewHeler.isShowBadge();
}
@Override
public BGABadgeViewHelper getBadgeViewHelper() {
return mBadgeViewHeler;
}
}

View File

@ -0,0 +1,97 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/7 14:07
* 描述:
*/
public class BGABadgeRelativeLayout extends RelativeLayout implements BGABadgeable {
private BGABadgeViewHelper mBadgeViewHeler;
public BGABadgeRelativeLayout(Context context) {
this(context, null);
}
public BGABadgeRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BGABadgeRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBadgeViewHeler = new BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightCenter);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mBadgeViewHeler.onTouchEvent(event);
}
@Override
public boolean callSuperOnTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
mBadgeViewHeler.drawBadge(canvas);
}
@Override
public void showCirclePointBadge() {
mBadgeViewHeler.showCirclePointBadge();
}
@Override
public void showTextBadge(String badgeText) {
mBadgeViewHeler.showTextBadge(badgeText);
}
@Override
public void hiddenBadge() {
mBadgeViewHeler.hiddenBadge();
}
@Override
public void showDrawableBadge(Bitmap bitmap) {
mBadgeViewHeler.showDrawable(bitmap);
}
@Override
public void setDragDismissDelegage(BGADragDismissDelegate delegate) {
mBadgeViewHeler.setDragDismissDelegage(delegate);
}
@Override
public boolean isShowBadge() {
return mBadgeViewHeler.isShowBadge();
}
@Override
public BGABadgeViewHelper getBadgeViewHelper() {
return mBadgeViewHeler;
}
}

View File

@ -0,0 +1,97 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.TextView;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/6 下午3:04
* 描述:
*/
public class BGABadgeTextView extends TextView implements BGABadgeable {
private BGABadgeViewHelper mBadgeViewHeler;
public BGABadgeTextView(Context context) {
this(context, null);
}
public BGABadgeTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public BGABadgeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBadgeViewHeler = new BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightCenter);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mBadgeViewHeler.onTouchEvent(event);
}
@Override
public boolean callSuperOnTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mBadgeViewHeler.drawBadge(canvas);
}
@Override
public void showCirclePointBadge() {
mBadgeViewHeler.showCirclePointBadge();
}
@Override
public void showTextBadge(String badgeText) {
mBadgeViewHeler.showTextBadge(badgeText);
}
@Override
public void hiddenBadge() {
mBadgeViewHeler.hiddenBadge();
}
@Override
public void showDrawableBadge(Bitmap bitmap) {
mBadgeViewHeler.showDrawable(bitmap);
}
@Override
public void setDragDismissDelegage(BGADragDismissDelegate delegate) {
mBadgeViewHeler.setDragDismissDelegage(delegate);
}
@Override
public boolean isShowBadge() {
return mBadgeViewHeler.isShowBadge();
}
@Override
public BGABadgeViewHelper getBadgeViewHelper() {
return mBadgeViewHeler;
}
}

View File

@ -0,0 +1,81 @@
package cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:16/3/14 上午2:46
* 描述:
*/
public class BGABadgeView extends View implements BGABadgeable {
private BGABadgeViewHelper mBadgeViewHeler;
public BGABadgeView(Context context) {
this(context, null);
}
public BGABadgeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BGABadgeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBadgeViewHeler = new BGABadgeViewHelper(this, context, attrs, BGABadgeViewHelper.BadgeGravity.RightCenter);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mBadgeViewHeler.onTouchEvent(event);
}
@Override
public boolean callSuperOnTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mBadgeViewHeler.drawBadge(canvas);
}
@Override
public void showCirclePointBadge() {
mBadgeViewHeler.showCirclePointBadge();
}
@Override
public void showTextBadge(String badgeText) {
mBadgeViewHeler.showTextBadge(badgeText);
}
@Override
public void hiddenBadge() {
mBadgeViewHeler.hiddenBadge();
}
@Override
public void showDrawableBadge(Bitmap bitmap) {
mBadgeViewHeler.showDrawable(bitmap);
}
@Override
public void setDragDismissDelegage(BGADragDismissDelegate delegate) {
mBadgeViewHeler.setDragDismissDelegage(delegate);
}
@Override
public boolean isShowBadge() {
return mBadgeViewHeler.isShowBadge();
}
@Override
public BGABadgeViewHelper getBadgeViewHelper() {
return mBadgeViewHeler;
}
}

View File

@ -0,0 +1,513 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/6 下午10:13
* 描述:
*/
public class BGABadgeViewHelper {
private Bitmap mBitmap;
private BGABadgeable mBadgeable;
private Paint mBadgePaint;
/**
* 徽章背景色
*/
private int mBadgeBgColor;
/**
* 徽章文本的颜色
*/
private int mBadgeTextColor;
/**
* 徽章文本字体大小
*/
private int mBadgeTextSize;
/**
* 徽章背景与宿主控件上下边缘间距离
*/
private int mBadgeVerticalMargin;
/**
* 徽章背景与宿主控件左右边缘间距离
*/
private int mBadgeHorizontalMargin;
/***
* 徽章文本边缘与徽章背景边缘间的距离
*/
private int mBadgePadding;
/**
* 徽章文本
*/
private String mBadgeText;
/**
* 徽章文本所占区域大小
*/
private Rect mBadgeNumberRect;
/**
* 是否显示Badge
*/
private boolean mIsShowBadge;
/**
* 徽章在宿主控件中的位置
*/
private BadgeGravity mBadgeGravity;
/**
* 整个徽章所占区域
*/
private RectF mBadgeRectF;
/**
* 是否可拖动
*/
private boolean mDragable;
/**
* 拖拽徽章超出轨迹范围后再次放回到轨迹范围时是否恢复轨迹
*/
private boolean mIsResumeTravel;
/***
* 徽章描边宽度
*/
private int mBadgeBorderWidth;
/***
* 徽章描边颜色
*/
private int mBadgeBorderColor;
/**
* 触发开始拖拽徽章事件的扩展触摸距离
*/
private int mDragExtra;
/**
* 整个徽章加上其触发开始拖拽区域所占区域
*/
private RectF mBadgeDragExtraRectF;
/**
* 拖动时的徽章控件
*/
private BGADragBadgeView mDropBadgeView;
/**
* 是否正在拖动
*/
private boolean mIsDraging;
/**
* 拖动大于BGABadgeViewHelper.mMoveHiddenThreshold后抬起手指徽章消失的代理
*/
private BGADragDismissDelegate mDelegage;
private boolean mIsShowDrawable = false;
public BGABadgeViewHelper(BGABadgeable badgeable, Context context, AttributeSet attrs, BadgeGravity defaultBadgeGravity) {
mBadgeable = badgeable;
initDefaultAttrs(context, defaultBadgeGravity);
initCustomAttrs(context, attrs);
afterInitDefaultAndCustomAttrs();
mDropBadgeView = new BGADragBadgeView(context, this);
}
private void initDefaultAttrs(Context context, BadgeGravity defaultBadgeGravity) {
mBadgeNumberRect = new Rect();
mBadgeRectF = new RectF();
mBadgeBgColor = Color.RED;
mBadgeTextColor = Color.WHITE;
mBadgeTextSize = BGABadgeViewUtil.sp2px(context, 10);
mBadgePaint = new Paint();
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);
// 设置mBadgeText居中保证mBadgeText长度为1时文本也能居中
mBadgePaint.setTextAlign(Paint.Align.CENTER);
mBadgePadding = BGABadgeViewUtil.dp2px(context, 4);
mBadgeVerticalMargin = BGABadgeViewUtil.dp2px(context, 4);
mBadgeHorizontalMargin = BGABadgeViewUtil.dp2px(context, 4);
mBadgeGravity = defaultBadgeGravity;
mIsShowBadge = false;
mBadgeText = null;
mBitmap = null;
mIsDraging = false;
mDragable = false;
mBadgeBorderColor = Color.WHITE;
mDragExtra = BGABadgeViewUtil.dp2px(context, 4);
mBadgeDragExtraRectF = new RectF();
}
private void initCustomAttrs(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BGABadgeView);
final int N = typedArray.getIndexCount();
for (int i = 0; i < N; i++) {
initCustomAttr(typedArray.getIndex(i), typedArray);
}
typedArray.recycle();
}
private void initCustomAttr(int attr, TypedArray typedArray) {
if (attr == R.styleable.BGABadgeView_badge_bgColor) {
mBadgeBgColor = typedArray.getColor(attr, mBadgeBgColor);
} else if (attr == R.styleable.BGABadgeView_badge_textColor) {
mBadgeTextColor = typedArray.getColor(attr, mBadgeTextColor);
} else if (attr == R.styleable.BGABadgeView_badge_textSize) {
mBadgeTextSize = typedArray.getDimensionPixelSize(attr, mBadgeTextSize);
} else if (attr == R.styleable.BGABadgeView_badge_verticalMargin) {
mBadgeVerticalMargin = typedArray.getDimensionPixelSize(attr, mBadgeVerticalMargin);
} else if (attr == R.styleable.BGABadgeView_badge_horizontalMargin) {
mBadgeHorizontalMargin = typedArray.getDimensionPixelSize(attr, mBadgeHorizontalMargin);
} else if (attr == R.styleable.BGABadgeView_badge_padding) {
mBadgePadding = typedArray.getDimensionPixelSize(attr, mBadgePadding);
} else if (attr == R.styleable.BGABadgeView_badge_gravity) {
int ordinal = typedArray.getInt(attr, mBadgeGravity.ordinal());
mBadgeGravity = BadgeGravity.values()[ordinal];
} else if (attr == R.styleable.BGABadgeView_badge_dragable) {
mDragable = typedArray.getBoolean(attr, mDragable);
} else if (attr == R.styleable.BGABadgeView_badge_isResumeTravel) {
mIsResumeTravel = typedArray.getBoolean(attr, mIsResumeTravel);
} else if (attr == R.styleable.BGABadgeView_badge_borderWidth) {
mBadgeBorderWidth = typedArray.getDimensionPixelSize(attr, mBadgeBorderWidth);
} else if (attr == R.styleable.BGABadgeView_badge_borderColor) {
mBadgeBorderColor = typedArray.getColor(attr, mBadgeBorderColor);
} else if (attr == R.styleable.BGABadgeView_badge_dragExtra) {
mDragExtra = typedArray.getDimensionPixelSize(attr, mDragExtra);
}
}
private void afterInitDefaultAndCustomAttrs() {
mBadgePaint.setTextSize(mBadgeTextSize);
}
public void setBadgeBgColorInt(int badgeBgColor) {
mBadgeBgColor = badgeBgColor;
mBadgeable.postInvalidate();
}
public void setBadgeTextColorInt(int badgeTextColor) {
mBadgeTextColor = badgeTextColor;
mBadgeable.postInvalidate();
}
public void setBadgeTextSizeSp(int badgetextSize) {
if (badgetextSize >= 0) {
mBadgeTextSize = BGABadgeViewUtil.sp2px(mBadgeable.getContext(), badgetextSize);
mBadgePaint.setTextSize(mBadgeTextSize);
mBadgeable.postInvalidate();
}
}
public void setBadgeVerticalMarginDp(int badgeVerticalMargin) {
if (badgeVerticalMargin >= 0) {
mBadgeVerticalMargin = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgeVerticalMargin);
mBadgeable.postInvalidate();
}
}
public void setBadgeHorizontalMarginDp(int badgeHorizontalMargin) {
if (badgeHorizontalMargin >= 0) {
mBadgeHorizontalMargin = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgeHorizontalMargin);
mBadgeable.postInvalidate();
}
}
public void setBadgePaddingDp(int badgePadding) {
if (badgePadding >= 0) {
mBadgePadding = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgePadding);
mBadgeable.postInvalidate();
}
}
public void setBadgeGravity(BadgeGravity badgeGravity) {
if (badgeGravity != null) {
mBadgeGravity = badgeGravity;
mBadgeable.postInvalidate();
}
}
public void setDragable(boolean dragable) {
mDragable = dragable;
mBadgeable.postInvalidate();
}
public void setIsResumeTravel(boolean isResumeTravel) {
mIsResumeTravel = isResumeTravel;
mBadgeable.postInvalidate();
}
public void setBadgeBorderWidthDp(int badgeBorderWidthDp) {
if (badgeBorderWidthDp >= 0) {
mBadgeBorderWidth = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgeBorderWidthDp);
mBadgeable.postInvalidate();
}
}
public void setBadgeBorderColorInt(int badgeBorderColor) {
mBadgeBorderColor = badgeBorderColor;
mBadgeable.postInvalidate();
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mBadgeDragExtraRectF.left = mBadgeRectF.left - mDragExtra;
mBadgeDragExtraRectF.top = mBadgeRectF.top - mDragExtra;
mBadgeDragExtraRectF.right = mBadgeRectF.right + mDragExtra;
mBadgeDragExtraRectF.bottom = mBadgeRectF.bottom + mDragExtra;
if ((mBadgeBorderWidth == 0 || mIsShowDrawable) && mDragable && mIsShowBadge && mBadgeDragExtraRectF.contains(event.getX(), event.getY())) {
mIsDraging = true;
mBadgeable.getParent().requestDisallowInterceptTouchEvent(true);
Rect badgeableRect = new Rect();
mBadgeable.getGlobalVisibleRect(badgeableRect);
mDropBadgeView.setStickCenter(badgeableRect.left + mBadgeRectF.left + mBadgeRectF.width() / 2, badgeableRect.top + mBadgeRectF.top + mBadgeRectF.height() / 2);
mDropBadgeView.onTouchEvent(event);
mBadgeable.postInvalidate();
return true;
}
break;
case MotionEvent.ACTION_MOVE:
if (mIsDraging) {
mDropBadgeView.onTouchEvent(event);
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mIsDraging) {
mDropBadgeView.onTouchEvent(event);
mIsDraging = false;
return true;
}
break;
default:
break;
}
return mBadgeable.callSuperOnTouchEvent(event);
}
public void endDragWithDismiss() {
hiddenBadge();
if (mDelegage != null) {
mDelegage.onDismiss(mBadgeable);
}
}
public void endDragWithoutDismiss() {
mBadgeable.postInvalidate();
}
public void drawBadge(Canvas canvas) {
if (mIsShowBadge && !mIsDraging) {
if (mIsShowDrawable) {
drawDrawableBadge(canvas);
} else {
drawTextBadge(canvas);
}
}
}
/**
* 绘制图像徽章
*
* @param canvas
*/
private void drawDrawableBadge(Canvas canvas) {
mBadgeRectF.left = mBadgeable.getWidth() - mBadgeHorizontalMargin - mBitmap.getWidth();
mBadgeRectF.top = mBadgeVerticalMargin;
switch (mBadgeGravity) {
case RightTop:
mBadgeRectF.top = mBadgeVerticalMargin;
break;
case RightCenter:
mBadgeRectF.top = (mBadgeable.getHeight() - mBitmap.getHeight()) / 2;
break;
case RightBottom:
mBadgeRectF.top = mBadgeable.getHeight() - mBitmap.getHeight() - mBadgeVerticalMargin;
break;
default:
break;
}
canvas.drawBitmap(mBitmap, mBadgeRectF.left, mBadgeRectF.top, mBadgePaint);
mBadgeRectF.right = mBadgeRectF.left + mBitmap.getWidth();
mBadgeRectF.bottom = mBadgeRectF.top + mBitmap.getHeight();
}
/**
* 绘制文字徽章
*
* @param canvas
*/
private void drawTextBadge(Canvas canvas) {
String badgeText = "";
if (!TextUtils.isEmpty(mBadgeText)) {
badgeText = mBadgeText;
}
// 获取文本宽所占宽高
mBadgePaint.getTextBounds(badgeText, 0, badgeText.length(), mBadgeNumberRect);
// 计算徽章背景的宽高
int badgeHeight = mBadgeNumberRect.height() + mBadgePadding * 2;
int badgeWidth;
// 当mBadgeText的长度为1或0时计算出来的高度会比宽度大此时设置宽度等于高度
if (badgeText.length() == 1 || badgeText.length() == 0) {
badgeWidth = badgeHeight;
} else {
badgeWidth = mBadgeNumberRect.width() + mBadgePadding * 2;
}
// 计算徽章背景上下的值
mBadgeRectF.top = mBadgeVerticalMargin;
mBadgeRectF.bottom = mBadgeable.getHeight() - mBadgeVerticalMargin;
switch (mBadgeGravity) {
case RightTop:
mBadgeRectF.bottom = mBadgeRectF.top + badgeHeight;
break;
case RightCenter:
mBadgeRectF.top = (mBadgeable.getHeight() - badgeHeight) / 2;
mBadgeRectF.bottom = mBadgeRectF.top + badgeHeight;
break;
case RightBottom:
mBadgeRectF.top = mBadgeRectF.bottom - badgeHeight;
break;
default:
break;
}
// 计算徽章背景左右的值
mBadgeRectF.right = mBadgeable.getWidth() - mBadgeHorizontalMargin;
mBadgeRectF.left = mBadgeRectF.right - badgeWidth;
if (mBadgeBorderWidth > 0) {
// 设置徽章边框景色
mBadgePaint.setColor(mBadgeBorderColor);
// 绘制徽章边框背景
canvas.drawRoundRect(mBadgeRectF, badgeHeight / 2, badgeHeight / 2, mBadgePaint);
// 设置徽章背景色
mBadgePaint.setColor(mBadgeBgColor);
// 绘制徽章背景
canvas.drawRoundRect(new RectF(mBadgeRectF.left + mBadgeBorderWidth, mBadgeRectF.top + mBadgeBorderWidth, mBadgeRectF.right - mBadgeBorderWidth, mBadgeRectF.bottom - mBadgeBorderWidth), (badgeHeight - 2 * mBadgeBorderWidth) / 2, (badgeHeight - 2 * mBadgeBorderWidth) / 2, mBadgePaint);
} else {
// 设置徽章背景色
mBadgePaint.setColor(mBadgeBgColor);
// 绘制徽章背景
canvas.drawRoundRect(mBadgeRectF, badgeHeight / 2, badgeHeight / 2, mBadgePaint);
}
if (!TextUtils.isEmpty(mBadgeText)) {
// 设置徽章文本颜色
mBadgePaint.setColor(mBadgeTextColor);
// initDefaultAttrs方法中设置了mBadgeText居中此处的x为徽章背景的中心点y
float x = mBadgeRectF.left + badgeWidth / 2;
// 注意绘制文本时的y是指文本底部而不是文本的中间
float y = mBadgeRectF.bottom - mBadgePadding;
// 绘制徽章文本
canvas.drawText(badgeText, x, y, mBadgePaint);
}
}
public void showCirclePointBadge() {
showTextBadge(null);
}
public void showTextBadge(String badgeText) {
mIsShowDrawable = false;
mBadgeText = badgeText;
mIsShowBadge = true;
mBadgeable.postInvalidate();
}
public void hiddenBadge() {
mIsShowBadge = false;
mBadgeable.postInvalidate();
}
public boolean isShowBadge() {
return mIsShowBadge;
}
public void showDrawable(Bitmap bitmap) {
mBitmap = bitmap;
mIsShowDrawable = true;
mIsShowBadge = true;
mBadgeable.postInvalidate();
}
public boolean isShowDrawable() {
return mIsShowDrawable;
}
public RectF getBadgeRectF() {
return mBadgeRectF;
}
public int getBadgePadding() {
return mBadgePadding;
}
public String getBadgeText() {
return mBadgeText;
}
public int getBadgeBgColor() {
return mBadgeBgColor;
}
public int getBadgeTextColor() {
return mBadgeTextColor;
}
public int getBadgeTextSize() {
return mBadgeTextSize;
}
public Bitmap getBitmap() {
return mBitmap;
}
public void setDragDismissDelegage(BGADragDismissDelegate delegage) {
mDelegage = delegage;
}
public View getRootView() {
return mBadgeable.getRootView();
}
public boolean isResumeTravel() {
return mIsResumeTravel;
}
public enum BadgeGravity {
RightTop,
RightCenter,
RightBottom
}
}

View File

@ -0,0 +1,100 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.TypedValue;
import android.view.View;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/12/5 上午12:27
* 描述:
*/
public class BGABadgeViewUtil {
private BGABadgeViewUtil() {
}
public static int dp2px(Context context, float dpValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.getResources().getDisplayMetrics());
}
public static int sp2px(Context context, float spValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.getResources().getDisplayMetrics());
}
public static int getStatusBarHeight(View view) {
Rect rectangle = new Rect();
view.getRootView().getWindowVisibleDisplayFrame(rectangle);
return rectangle.top;
}
public static Bitmap createBitmapSafely(BGADragBadgeView dragBadgeView, Rect rect, int retryCount) {
try {
dragBadgeView.setDrawingCacheEnabled(true);
// 只裁剪徽章区域,不然会很卡
return Bitmap.createBitmap(dragBadgeView.getDrawingCache(), rect.left < 0 ? 0 : rect.left, rect.top < 0 ? 0 : rect.top, rect.width(), rect.height());
} catch (OutOfMemoryError e) {
if (retryCount > 0) {
System.gc();
return createBitmapSafely(dragBadgeView, rect, retryCount - 1);
}
return null;
}
}
public static float getDistanceBetween2Points(PointF p0, PointF p1) {
float distance = (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2));
return distance;
}
public static PointF getMiddlePoint(PointF p1, PointF p2) {
return new PointF((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f);
}
public static PointF getPointByPercent(PointF p1, PointF p2, float percent) {
return new PointF(evaluate(percent, p1.x, p2.x), evaluate(percent, p1.y, p2.y));
}
// 从FloatEvaluator中拷贝过来,这样就不用每次都new FloatEvaluator了
public static Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
public static PointF[] getIntersectionPoints(PointF pMiddle, float radius, Double lineK) {
PointF[] points = new PointF[2];
float radian, xOffset = 0, yOffset = 0;
if (lineK != null) {
radian = (float) Math.atan(lineK);
xOffset = (float) (Math.sin(radian) * radius);
yOffset = (float) (Math.cos(radian) * radius);
} else {
xOffset = radius;
yOffset = 0;
}
points[0] = new PointF(pMiddle.x + xOffset, pMiddle.y - yOffset);
points[1] = new PointF(pMiddle.x - xOffset, pMiddle.y + yOffset);
return points;
}
}

View File

@ -0,0 +1,95 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/6 下午10:42
* 描述:
*/
public interface BGABadgeable {
/**
* 显示圆点徽章
*/
void showCirclePointBadge();
/**
* 显示文字徽章
*
* @param badgeText
*/
void showTextBadge(String badgeText);
/**
* 隐藏徽章
*/
void hiddenBadge();
/**
* 显示图像徽章
*
* @param bitmap
*/
void showDrawableBadge(Bitmap bitmap);
/**
* 调用父类的onTouchEvent方法
*
* @param event
* @return
*/
boolean callSuperOnTouchEvent(MotionEvent event);
/**
* 拖动大于BGABadgeViewHelper.mMoveHiddenThreshold后抬起手指徽章消失的代理
*
* @param delegate
*/
void setDragDismissDelegage(BGADragDismissDelegate delegate);
/**
* 是否显示徽章
*
* @return
*/
boolean isShowBadge();
BGABadgeViewHelper getBadgeViewHelper();
int getWidth();
int getHeight();
void postInvalidate();
ViewParent getParent();
int getId();
boolean getGlobalVisibleRect(Rect r);
Context getContext();
View getRootView();
}

View File

@ -0,0 +1,478 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.OvershootInterpolator;
import java.lang.ref.WeakReference;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/12 下午3:23
* 描述:
*/
class BGADragBadgeView extends View {
private static final String TAG = BGADragBadgeView.class.getSimpleName();
private BGABadgeViewHelper mBadgeViewHelper;
private Paint mBadgePaint;
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;
private int mStartX;
private int mStartY;
private BGAExplosionAnimator mExplosionAnimator;
private SetExplosionAnimatorNullTask mSetExplosionAnimatorNullTask;
/**
* 针圆切线的切点
*/
private PointF[] mStickPoints = new PointF[]{
new PointF(0, 0),
new PointF(0, 0)
};
/**
* 拖拽圆切线的切点
*/
private PointF[] mDragPoints = new PointF[]{
new PointF(0, 0),
new PointF(0, 0)
};
/**
* 控制点
*/
private PointF mControlPoint = new PointF(0, 0);
/**
* 拖拽圆中心点
*/
private PointF mDragCenter = new PointF(0, 0);
/**
* 拖拽圆半径
*/
private float mDragRadius;
/**
* 针圆中心点
*/
private PointF mStickCenter;
/**
* 针圆半径
*/
private float mStickRadius;
/**
* 拖拽圆最大半径
*/
private int mMaxDragRadius;
/**
* 拖拽圆半径和针圆半径的差值
*/
private int mDragStickRadiusDifference;
/**
* 拖动mDismissThreshold距离后抬起手指徽章消失
*/
private int mDismissThreshold;
private boolean mDismissAble;
private boolean mIsDragDisappear;
public BGADragBadgeView(Context context, BGABadgeViewHelper badgeViewHelper) {
super(context);
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mBadgeViewHelper = badgeViewHelper;
initBadgePaint();
initLayoutParams();
initStick();
mSetExplosionAnimatorNullTask = new SetExplosionAnimatorNullTask(this);
}
private void initBadgePaint() {
mBadgePaint = new Paint();
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);
// 设置mBadgeText居中保证mBadgeText长度为1时文本也能居中
mBadgePaint.setTextAlign(Paint.Align.CENTER);
mBadgePaint.setTextSize(mBadgeViewHelper.getBadgeTextSize());
}
private void initLayoutParams() {
mLayoutParams = new WindowManager.LayoutParams();
mLayoutParams.gravity = Gravity.LEFT + Gravity.TOP;
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLayoutParams.format = PixelFormat.TRANSLUCENT;
mLayoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;
mLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
mLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
}
private void initStick() {
mMaxDragRadius = BGABadgeViewUtil.dp2px(getContext(), 10);
mDragStickRadiusDifference = BGABadgeViewUtil.dp2px(getContext(), 1);
}
@Override
protected void onDraw(Canvas canvas) {
try {
if (mExplosionAnimator == null) {
if (mBadgeViewHelper.isShowDrawable()) {
if (mBadgeViewHelper.getBadgeBgColor() == Color.RED) {
mBadgePaint.setColor(mBadgeViewHelper.getBitmap().getPixel(mBadgeViewHelper.getBitmap().getWidth() / 2, mBadgeViewHelper.getBitmap().getHeight() / 2));
} else {
mBadgePaint.setColor(mBadgeViewHelper.getBadgeBgColor());
}
drawStick(canvas);
drawDrawableBadge(canvas);
} else {
mBadgePaint.setColor(mBadgeViewHelper.getBadgeBgColor());
drawStick(canvas);
drawTextBadge(canvas);
}
} else {
mExplosionAnimator.draw(canvas);
}
} catch (Exception e) {
// 确保自己能被移除
removeSelfWithException();
}
}
private void drawDrawableBadge(Canvas canvas) {
canvas.drawBitmap(mBadgeViewHelper.getBitmap(), mStartX, mStartY, mBadgePaint);
}
private void drawTextBadge(Canvas canvas) {
// 设置徽章背景色
mBadgePaint.setColor(mBadgeViewHelper.getBadgeBgColor());
// 绘制徽章背景
canvas.drawRoundRect(new RectF(mStartX, mStartY, mStartX + mBadgeViewHelper.getBadgeRectF().width(), mStartY + mBadgeViewHelper.getBadgeRectF().height()), mBadgeViewHelper.getBadgeRectF().height() / 2, mBadgeViewHelper.getBadgeRectF().height() / 2, mBadgePaint);
// 设置徽章文本颜色
mBadgePaint.setColor(mBadgeViewHelper.getBadgeTextColor());
float x = mStartX + mBadgeViewHelper.getBadgeRectF().width() / 2;
// 注意绘制文本时的y是指文本底部而不是文本的中间
float y = mStartY + mBadgeViewHelper.getBadgeRectF().height() - mBadgeViewHelper.getBadgePadding();
// 绘制徽章文本
String badgeText = mBadgeViewHelper.getBadgeText() == null ? "" : mBadgeViewHelper.getBadgeText();
canvas.drawText(badgeText, x, y, mBadgePaint);
}
private void drawStick(Canvas canvas) {
float currentStickRadius = getCurrentStickRadius();
// 2. 获取直线与圆的交点
float yOffset = mStickCenter.y - mDragCenter.y;
float xOffset = mStickCenter.x - mDragCenter.x;
Double lineK = null;
if (xOffset != 0) {
lineK = (double) (yOffset / xOffset);
}
// 通过几何图形工具获取交点坐标
mDragPoints = BGABadgeViewUtil.getIntersectionPoints(mDragCenter, mDragRadius, lineK);
mStickPoints = BGABadgeViewUtil.getIntersectionPoints(mStickCenter, currentStickRadius, lineK);
// 3. 获取控制点坐标
mControlPoint = BGABadgeViewUtil.getMiddlePoint(mDragCenter, mStickCenter);
// 保存画布状态
canvas.save();
canvas.translate(0, -BGABadgeViewUtil.getStatusBarHeight(mBadgeViewHelper.getRootView()));
if (!mIsDragDisappear) {
if (!mDismissAble) {
// 3. 画连接部分
Path path = new Path();
// 跳到点1
path.moveTo(mStickPoints[0].x, mStickPoints[0].y);
// 画曲线1 -> 2
path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints[0].x, mDragPoints[0].y);
// 画直线2 -> 3
path.lineTo(mDragPoints[1].x, mDragPoints[1].y);
// 画曲线3 -> 4
path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints[1].x, mStickPoints[1].y);
path.close();
canvas.drawPath(path, mBadgePaint);
// 2. 画固定圆
canvas.drawCircle(mStickCenter.x, mStickCenter.y, currentStickRadius, mBadgePaint);
}
// 1. 画拖拽圆
canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, mBadgePaint);
}
// 恢复上次的保存状态
canvas.restore();
}
/**
* 获取针圆实时半径
*
* @return
*/
private float getCurrentStickRadius() {
/**
* distance 0 -> mDismissThreshold
* percent 0.0f -> 1.0f
* currentStickRadius mStickRadius * 100% -> mStickRadius * 20%
*/
float distance = BGABadgeViewUtil.getDistanceBetween2Points(mDragCenter, mStickCenter);
distance = Math.min(distance, mDismissThreshold);
float percent = distance / mDismissThreshold;
return BGABadgeViewUtil.evaluate(percent, mStickRadius, mStickRadius * 0.2f);
}
public void setStickCenter(float x, float y) {
mStickCenter = new PointF(x, y);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
handleActionDown(event);
break;
case MotionEvent.ACTION_MOVE:
handleActionMove(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
handleActionUp(event);
break;
}
} catch (Exception e) {
// 确保自己能被移除
removeSelfWithException();
}
return true;
}
private void handleActionDown(MotionEvent event) {
if (mExplosionAnimator == null && getParent() == null) {
mDragRadius = Math.min(mBadgeViewHelper.getBadgeRectF().width() / 2, mMaxDragRadius);
mStickRadius = mDragRadius - mDragStickRadiusDifference;
mDismissThreshold = (int) (mStickRadius * 10);
mDismissAble = false;
mIsDragDisappear = false;
mWindowManager.addView(this, mLayoutParams);
updateDragPosition(event.getRawX(), event.getRawY());
}
}
private void handleActionMove(MotionEvent event) {
if (mExplosionAnimator == null && getParent() != null) {
updateDragPosition(event.getRawX(), event.getRawY());
// 处理断开事件
if (BGABadgeViewUtil.getDistanceBetween2Points(mDragCenter, mStickCenter) > mDismissThreshold) {
mDismissAble = true;
postInvalidate();
} else if (mBadgeViewHelper.isResumeTravel()) {
mDismissAble = false;
postInvalidate();
}
}
}
private void handleActionUp(MotionEvent event) {
handleActionMove(event);
if (mDismissAble) {
// 拖拽点超出过范围
if (BGABadgeViewUtil.getDistanceBetween2Points(mDragCenter, mStickCenter) > mDismissThreshold) {
// 现在也超出范围,消失
try {
mIsDragDisappear = true;
startDismissAnim(getNewStartX(event.getRawX()), getNewStartY(event.getRawY()));
} catch (Exception e) {
removeSelf();
mBadgeViewHelper.endDragWithDismiss();
}
} else {
// 现在没有超出范围,放回去
removeSelf();
mBadgeViewHelper.endDragWithoutDismiss();
}
} else {
// 拖拽点没超出过范围,弹回去
try {
startSpringAnim();
} catch (Exception e) {
removeSelf();
mBadgeViewHelper.endDragWithoutDismiss();
}
}
}
private void startSpringAnim() {
final PointF startReleaseDragCenter = new PointF(mDragCenter.x, mDragCenter.y);
ValueAnimator springAnim = ValueAnimator.ofFloat(1.0f);
springAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator mAnim) {
// 0.0 -> 1.0f
float percent = mAnim.getAnimatedFraction();
PointF p = BGABadgeViewUtil.getPointByPercent(startReleaseDragCenter, mStickCenter, percent);
updateDragPosition(p.x, p.y);
}
});
springAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
removeSelf();
mBadgeViewHelper.endDragWithoutDismiss();
}
@Override
public void onAnimationCancel(Animator animation) {
removeSelf();
mBadgeViewHelper.endDragWithoutDismiss();
}
});
springAnim.setInterpolator(new OvershootInterpolator(4));
springAnim.setRepeatCount(1);
springAnim.setRepeatMode(ValueAnimator.INFINITE);
springAnim.setDuration(BGAExplosionAnimator.ANIM_DURATION / 2);
springAnim.start();
}
private void startDismissAnim(int newX, int newY) {
int badgeWidth = (int) mBadgeViewHelper.getBadgeRectF().width();
int badgeHeight = (int) mBadgeViewHelper.getBadgeRectF().height();
Rect rect = new Rect(newX - badgeWidth / 2, newY - badgeHeight / 2, newX + badgeWidth / 2, newY + badgeHeight / 2);
Bitmap badgeBitmap = BGABadgeViewUtil.createBitmapSafely(this, rect, 1);
if (badgeBitmap == null) {
removeSelf();
mBadgeViewHelper.endDragWithDismiss();
return;
}
if (mExplosionAnimator != null) {
removeSelf();
mBadgeViewHelper.endDragWithDismiss();
return;
}
mExplosionAnimator = new BGAExplosionAnimator(this, rect, badgeBitmap);
mExplosionAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
removeSelf();
mBadgeViewHelper.endDragWithDismiss();
}
@Override
public void onAnimationCancel(Animator animation) {
removeSelf();
mBadgeViewHelper.endDragWithDismiss();
}
});
mExplosionAnimator.start();
}
private void removeSelf() {
if (getParent() != null) {
mWindowManager.removeView(this);
}
mDismissAble = false;
mIsDragDisappear = false;
// 处理有时候爆炸效果结束后出现一瞬间的拖拽效果
postDelayed(mSetExplosionAnimatorNullTask, 60);
}
/**
* 修改拖拽位置
*
* @param rawX
* @param rawY
*/
private void updateDragPosition(float rawX, float rawY) {
mStartX = getNewStartX(rawX);
mStartY = getNewStartY(rawY);
mDragCenter.set(rawX, rawY);
postInvalidate();
}
private int getNewStartX(float rawX) {
int badgeWidth = (int) mBadgeViewHelper.getBadgeRectF().width();
int newX = (int) rawX - badgeWidth / 2;
if (newX < 0) {
newX = 0;
}
if (newX > mWindowManager.getDefaultDisplay().getWidth() - badgeWidth) {
newX = mWindowManager.getDefaultDisplay().getWidth() - badgeWidth;
}
return newX;
}
private int getNewStartY(float rawY) {
int badgeHeight = (int) mBadgeViewHelper.getBadgeRectF().height();
int maxNewY = getHeight() - badgeHeight;
int newStartY = (int) rawY - badgeHeight / 2 - BGABadgeViewUtil.getStatusBarHeight(mBadgeViewHelper.getRootView());
return Math.min(Math.max(0, newStartY), maxNewY);
}
private void removeSelfWithException() {
removeSelf();
if (BGABadgeViewUtil.getDistanceBetween2Points(mDragCenter, mStickCenter) > mDismissThreshold) {
mBadgeViewHelper.endDragWithDismiss();
} else {
mBadgeViewHelper.endDragWithoutDismiss();
}
}
private static class SetExplosionAnimatorNullTask implements Runnable {
private final WeakReference<BGADragBadgeView> mDragBadgeView;
public SetExplosionAnimatorNullTask(BGADragBadgeView dragBadgeView) {
mDragBadgeView = new WeakReference<>(dragBadgeView);
}
@Override
public void run() {
BGADragBadgeView dragBadgeView = mDragBadgeView.get();
if (dragBadgeView != null) {
dragBadgeView.mExplosionAnimator = null;
}
}
}
}

View File

@ -0,0 +1,32 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/7/12 下午6:33
* 描述:拖动大于BGABadgeViewHelper.mMoveHiddenThreshold后抬起手指徽章消失的代理
*/
public interface BGADragDismissDelegate {
/**
* 拖动大于BGABadgeViewHelper.mMoveHiddenThreshold后抬起手指徽章消失的回调方法
*
* @param badgeable
*/
void onDismiss(BGABadgeable badgeable);
}

View File

@ -0,0 +1,170 @@
/**
* Copyright 2015 bingoogolapple
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 cn.bingoogolapple.badgeview;
import android.animation.ValueAnimator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import java.util.Random;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/12/5 上午12:21
* 描述:参考https://github.com/tyrantgit/ExplosionField改成了只有一个View的情况,只刷新徽章附近的区域
*/
public class BGAExplosionAnimator extends ValueAnimator {
public static final int ANIM_DURATION = 300;
private static final Interpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator(0.6f);
private static final float END_VALUE = 1.4f;
private static final int REFRESH_RATIO = 3;
private static float X;
private static float Y;
private static float V;
private static float W;
private Particle[] mParticles;
private Paint mPaint;
private BGADragBadgeView mDragBadgeView;
private Rect mRect;
private Rect mInvalidateRect;
public BGAExplosionAnimator(BGADragBadgeView dragBadgeView, Rect rect, Bitmap bitmap) {
setFloatValues(0.0f, END_VALUE);
setDuration(ANIM_DURATION);
setInterpolator(DEFAULT_INTERPOLATOR);
X = BGABadgeViewUtil.dp2px(dragBadgeView.getContext(), 5);
Y = BGABadgeViewUtil.dp2px(dragBadgeView.getContext(), 20);
V = BGABadgeViewUtil.dp2px(dragBadgeView.getContext(), 2);
W = BGABadgeViewUtil.dp2px(dragBadgeView.getContext(), 1);
mPaint = new Paint();
mDragBadgeView = dragBadgeView;
mRect = rect;
mInvalidateRect = new Rect(mRect.left - mRect.width() * REFRESH_RATIO, mRect.top - mRect.height() * REFRESH_RATIO, mRect.right + mRect.width() * REFRESH_RATIO, mRect.bottom + mRect.height() * REFRESH_RATIO);
int partLen = 15;
mParticles = new Particle[partLen * partLen];
Random random = new Random(System.currentTimeMillis());
int w = bitmap.getWidth() / (partLen + 2);
int h = bitmap.getHeight() / (partLen + 2);
for (int i = 0; i < partLen; i++) {
for (int j = 0; j < partLen; j++) {
mParticles[(i * partLen) + j] = generateParticle(bitmap.getPixel((j + 1) * w, (i + 1) * h), random);
}
}
}
private Particle generateParticle(int color, Random random) {
Particle particle = new Particle();
particle.color = color;
particle.radius = V;
if (random.nextFloat() < 0.2f) {
particle.baseRadius = V + ((X - V) * random.nextFloat());
} else {
particle.baseRadius = W + ((V - W) * random.nextFloat());
}
float nextFloat = random.nextFloat();
particle.top = mRect.height() * ((0.18f * random.nextFloat()) + 0.2f);
particle.top = nextFloat < 0.2f ? particle.top : particle.top + ((particle.top * 0.2f) * random.nextFloat());
particle.bottom = (mRect.height() * (random.nextFloat() - 0.5f)) * 1.8f;
float f = nextFloat < 0.2f ? particle.bottom : nextFloat < 0.8f ? particle.bottom * 0.6f : particle.bottom * 0.3f;
particle.bottom = f;
particle.mag = 4.0f * particle.top / particle.bottom;
particle.neg = (-particle.mag) / particle.bottom;
f = mRect.centerX() + (Y * (random.nextFloat() - 0.5f));
particle.baseCx = f + mRect.width() / 2;
particle.cx = particle.baseCx;
f = mRect.centerY() + (Y * (random.nextFloat() - 0.5f));
particle.baseCy = f;
particle.cy = f;
particle.life = END_VALUE / 10 * random.nextFloat();
particle.overflow = 0.4f * random.nextFloat();
particle.alpha = 1f;
return particle;
}
public void draw(Canvas canvas) {
if (!isStarted()) {
return;
}
for (Particle particle : mParticles) {
particle.advance((float) getAnimatedValue());
if (particle.alpha > 0f) {
mPaint.setColor(particle.color);
mPaint.setAlpha((int) (Color.alpha(particle.color) * particle.alpha));
canvas.drawCircle(particle.cx, particle.cy, particle.radius, mPaint);
}
}
postInvalidate();
}
@Override
public void start() {
super.start();
postInvalidate();
}
/**
* 只刷新徽章附近的区域
*/
private void postInvalidate() {
mDragBadgeView.postInvalidate(mInvalidateRect.left, mInvalidateRect.top, mInvalidateRect.right, mInvalidateRect.bottom);
}
private class Particle {
float alpha;
int color;
float cx;
float cy;
float radius;
float baseCx;
float baseCy;
float baseRadius;
float top;
float bottom;
float mag;
float neg;
float life;
float overflow;
public void advance(float factor) {
float f = 0f;
float normalization = factor / END_VALUE;
if (normalization < life || normalization > 1f - overflow) {
alpha = 0f;
return;
}
normalization = (normalization - life) / (1f - life - overflow);
float f2 = normalization * END_VALUE;
if (normalization >= 0.7f) {
f = (normalization - 0.7f) / 0.3f;
}
alpha = 1f - f;
f = bottom * f2;
cx = baseCx + f;
cy = (float) (baseCy - this.neg * Math.pow(f, 2.0)) - f * mag;
radius = V + (baseRadius - V) * f2;
}
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BGABadgeView">
<!-- 徽章背景色 -->
<attr name="badge_bgColor" format="reference|color" />
<!-- 徽章文本的颜色 -->
<attr name="badge_textColor" format="reference|color" />
<!-- 徽章文本字体大小 -->
<attr name="badge_textSize" format="reference|dimension" />
<!-- 徽章背景与宿主控件上下边缘间距离 -->
<attr name="badge_verticalMargin" format="reference|dimension" />
<!-- 徽章背景与宿主控件左右边缘间距离 -->
<attr name="badge_horizontalMargin" format="reference|dimension" />
<!-- 徽章文本边缘与徽章背景边缘间的距离 -->
<attr name="badge_padding" format="reference|dimension" />
<!-- 徽章在宿主控件中的位置 -->
<attr name="badge_gravity" format="enum">
<enum name="rightTop" value="0" />
<enum name="rightCenter" value="1" />
<enum name="rightBottom" value="2" />
</attr>
<!-- 是否可以拖拽删除徽章 -->
<attr name="badge_dragable" format="boolean" />
<!-- 拖拽徽章超出轨迹范围后,再次放回到轨迹范围时,是否恢复轨迹 -->
<attr name="badge_isResumeTravel" format="boolean" />
<!-- 徽章描边宽度 -->
<attr name="badge_borderWidth" format="reference|dimension" />
<!-- 徽章描边颜色 -->
<attr name="badge_borderColor" format="reference|color" />
<!-- 触发开始拖拽徽章事件的扩展触摸距离-->
<attr name="badge_dragExtra" format="reference|dimension" />
</declare-styleable>
</resources>

View File

@ -0,0 +1,29 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 59
versionName "5.5.4"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.3.1'
}

17
JCVideo_Library/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/Nathen/WorkEnv/android-sdk-macosx/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,13 @@
package fm.jiecao.jcvideoplayer_lib;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fm.jiecao.jcvideoplayer_lib">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View File

@ -0,0 +1,234 @@
package fm.jiecao.jcvideoplayer_lib;
import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import java.lang.reflect.Method;
import java.util.Map;
/**
* <p>统一管理MediaPlayer的地方,只有一个mediaPlayer实例那么不会有多个视频同时播放也节省资源</p>
* <p>Unified management MediaPlayer place, there is only one MediaPlayer instance, then there will be no more video broadcast at the same time, also save resources.</p>
* Created by Nathen
* On 2015/11/30 15:39
*/
public class JCMediaManager implements TextureView.SurfaceTextureListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener, MediaPlayer.OnVideoSizeChangedListener {
public static String TAG = "JieCaoVideoPlayer";
private static JCMediaManager JCMediaManager;
public static JCResizeTextureView textureView;
public static SurfaceTexture savedSurfaceTexture;
public MediaPlayer mediaPlayer = new MediaPlayer();
public static String CURRENT_PLAYING_URL;
public static boolean CURRENT_PLING_LOOP;
public static Map<String, String> MAP_HEADER_DATA;
public int currentVideoWidth = 0;
public int currentVideoHeight = 0;
public static final int HANDLER_PREPARE = 0;
public static final int HANDLER_RELEASE = 2;
HandlerThread mMediaHandlerThread;
MediaHandler mMediaHandler;
Handler mainThreadHandler;
public static JCMediaManager instance() {
if (JCMediaManager == null) {
JCMediaManager = new JCMediaManager();
}
return JCMediaManager;
}
public JCMediaManager() {
mMediaHandlerThread = new HandlerThread(TAG);
mMediaHandlerThread.start();
mMediaHandler = new MediaHandler((mMediaHandlerThread.getLooper()));
mainThreadHandler = new Handler();
}
public Point getVideoSize() {
if (currentVideoWidth != 0 && currentVideoHeight != 0) {
return new Point(currentVideoWidth, currentVideoHeight);
} else {
return null;
}
}
public class MediaHandler extends Handler {
public MediaHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case HANDLER_PREPARE:
try {
currentVideoWidth = 0;
currentVideoHeight = 0;
mediaPlayer.release();
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
Class<MediaPlayer> clazz = MediaPlayer.class;
Method method = clazz.getDeclaredMethod("setDataSource", String.class, Map.class);
method.invoke(mediaPlayer, CURRENT_PLAYING_URL, MAP_HEADER_DATA);
mediaPlayer.setLooping(CURRENT_PLING_LOOP);
mediaPlayer.setOnPreparedListener(JCMediaManager.this);
mediaPlayer.setOnCompletionListener(JCMediaManager.this);
mediaPlayer.setOnBufferingUpdateListener(JCMediaManager.this);
mediaPlayer.setScreenOnWhilePlaying(true);
mediaPlayer.setOnSeekCompleteListener(JCMediaManager.this);
mediaPlayer.setOnErrorListener(JCMediaManager.this);
mediaPlayer.setOnInfoListener(JCMediaManager.this);
mediaPlayer.setOnVideoSizeChangedListener(JCMediaManager.this);
mediaPlayer.prepareAsync();
mediaPlayer.setSurface(new Surface(savedSurfaceTexture));
} catch (Exception e) {
e.printStackTrace();
}
break;
case HANDLER_RELEASE:
mediaPlayer.release();
break;
}
}
}
public void prepare() {
releaseMediaPlayer();
Message msg = new Message();
msg.what = HANDLER_PREPARE;
mMediaHandler.sendMessage(msg);
}
public void releaseMediaPlayer() {
Message msg = new Message();
msg.what = HANDLER_RELEASE;
mMediaHandler.sendMessage(msg);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
Log.i(TAG, "onSurfaceTextureAvailable [" + this.hashCode() + "] ");
if (savedSurfaceTexture == null) {
savedSurfaceTexture = surfaceTexture;
prepare();
} else {
textureView.setSurfaceTexture(savedSurfaceTexture);
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
// 如果SurfaceTexture还没有更新Image则记录SizeChanged事件否则忽略
Log.i(TAG, "onSurfaceTextureSizeChanged [" + this.hashCode() + "] ");
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return savedSurfaceTexture == null;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onPrepared();
}
}
});
}
@Override
public void onCompletion(MediaPlayer mp) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onAutoCompletion();
}
}
});
}
@Override
public void onBufferingUpdate(MediaPlayer mp, final int percent) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().setBufferProgress(percent);
}
}
});
}
@Override
public void onSeekComplete(MediaPlayer mp) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onSeekComplete();
}
}
});
}
@Override
public boolean onError(MediaPlayer mp, final int what, final int extra) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onError(what, extra);
}
}
});
return true;
}
@Override
public boolean onInfo(MediaPlayer mp, final int what, final int extra) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onInfo(what, extra);
}
}
});
return false;
}
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
currentVideoWidth = width;
currentVideoHeight = height;
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onVideoSizeChanged();
}
}
});
}
}

View File

@ -0,0 +1,128 @@
package fm.jiecao.jcvideoplayer_lib;
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.view.TextureView;
/**
* <p>参照Android系统的VideoView的onMeasure方法
* <br>注意!relativelayout中无法全屏要嵌套一个linearlayout</p>
* <p>Referring Android system Video View of onMeasure method
* <br>NOTE! Can not fullscreen relativelayout, to nest a linearlayout</p>
* Created by Nathen
* On 2016/06/02 00:01
*/
public class JCResizeTextureView extends TextureView {
protected static final String TAG = "JCResizeTextureView";
// x as width, y as height
protected Point mVideoSize;
public JCResizeTextureView(Context context) {
super(context);
init();
}
public JCResizeTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mVideoSize = new Point(0, 0);
}
public void setVideoSize(Point videoSize) {
if (videoSize != null && !mVideoSize.equals(videoSize)) {
this.mVideoSize = videoSize;
requestLayout();
}
}
@Override
public void setRotation(float rotation) {
if (rotation != getRotation()) {
super.setRotation(rotation);
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.i(TAG, "onMeasure " + " [" + this.hashCode() + "] ");
int viewRotation = (int) getRotation();
int videoWidth = mVideoSize.x;
int videoHeight = mVideoSize.y;
Log.i(TAG, "videoWidth = " + videoWidth + ", " + "videoHeight = " + videoHeight);
Log.i(TAG, "viewRotation = " + viewRotation);
// 如果判断成立则说明显示的TextureView和本身的位置是有90度的旋转的所以需要交换宽高参数
if (viewRotation == 90 || viewRotation == 270) {
int tempMeasureSpec = widthMeasureSpec;
widthMeasureSpec = heightMeasureSpec;
heightMeasureSpec = tempMeasureSpec;
}
int width = getDefaultSize(videoWidth, widthMeasureSpec);
int height = getDefaultSize(videoHeight, heightMeasureSpec);
if (videoWidth > 0 && videoHeight > 0) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
Log.i(TAG, "widthMeasureSpec [" + MeasureSpec.toString(widthMeasureSpec) + "]");
Log.i(TAG, "heightMeasureSpec [" + MeasureSpec.toString(heightMeasureSpec) + "]");
if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
// the size is fixed
width = widthSpecSize;
height = heightSpecSize;
// for compatibility, we adjust size based on aspect ratio
if (videoWidth * height < width * videoHeight) {
width = height * videoWidth / videoHeight;
} else if (videoWidth * height > width * videoHeight) {
height = width * videoHeight / videoWidth;
}
} else if (widthSpecMode == MeasureSpec.EXACTLY) {
// only the width is fixed, adjust the height to match aspect ratio if possible
width = widthSpecSize;
height = width * videoHeight / videoWidth;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// couldn't match aspect ratio within the constraints
height = heightSpecSize;
width = height * videoWidth / videoHeight;
}
} else if (heightSpecMode == MeasureSpec.EXACTLY) {
// only the height is fixed, adjust the width to match aspect ratio if possible
height = heightSpecSize;
width = height * videoWidth / videoHeight;
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// couldn't match aspect ratio within the constraints
width = widthSpecSize;
height = width * videoHeight / videoWidth;
}
} else {
// neither the width nor the height are fixed, try to use actual video size
width = videoWidth;
height = videoHeight;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// too tall, decrease both width and height
height = heightSpecSize;
width = height * videoWidth / videoHeight;
}
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// too wide, decrease both width and height
width = widthSpecSize;
height = width * videoHeight / videoWidth;
}
}
} else {
// no size yet, just adopt the given spec sizes
}
setMeasuredDimension(width, height);
}
}

View File

@ -0,0 +1,29 @@
package fm.jiecao.jcvideoplayer_lib;
/**
* Created by Nathen
* On 2016/04/04 22:13
*/
public interface JCUserAction {
int ON_CLICK_START_ICON = 0;
int ON_CLICK_START_ERROR = 1;
int ON_CLICK_START_AUTO_COMPLETE = 2;
int ON_CLICK_PAUSE = 3;
int ON_CLICK_RESUME = 4;
int ON_SEEK_POSITION = 5;
int ON_AUTO_COMPLETE = 6;
int ON_ENTER_FULLSCREEN = 7;
int ON_QUIT_FULLSCREEN = 8;
int ON_ENTER_TINYSCREEN = 9;
int ON_QUIT_TINYSCREEN = 10;
int ON_TOUCH_SCREEN_SEEK_VOLUME = 11;
int ON_TOUCH_SCREEN_SEEK_POSITION = 12;
void onEvent(int type, String url, int screen, Object... objects);
}

View File

@ -0,0 +1,12 @@
package fm.jiecao.jcvideoplayer_lib;
/**
* Created by Nathen
* On 2016/04/26 20:53
*/
public interface JCUserActionStandard extends JCUserAction {
int ON_CLICK_START_THUMB = 101;
int ON_CLICK_BLANK = 102;
}

View File

@ -0,0 +1,124 @@
package fm.jiecao.jcvideoplayer_lib;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ContextThemeWrapper;
import android.text.TextUtils;
import java.util.Formatter;
import java.util.Locale;
/**
* Created by Nathen
* On 2016/02/21 12:25
*/
public class JCUtils {
public static String stringForTime(int timeMs) {
if (timeMs <= 0 || timeMs >= 24 * 60 * 60 * 1000) {
return "00:00";
}
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
StringBuilder stringBuilder = new StringBuilder();
Formatter mFormatter = new Formatter(stringBuilder, Locale.getDefault());
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
/**
* This method requires the caller to hold the permission ACCESS_NETWORK_STATE.
*
* @param context a application context
* @return if wifi is connected,return true
*/
public static boolean isWifiConnected(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
}
/**
* Get activity from context object
*
* @param context something
* @return object of Activity or null if it is not Activity
*/
public static Activity scanForActivity(Context context) {
if (context == null) return null;
if (context instanceof Activity) {
return (Activity) context;
} else if (context instanceof ContextWrapper) {
return scanForActivity(((ContextWrapper) context).getBaseContext());
}
return null;
}
/**
* Get AppCompatActivity from context
*
* @param context
* @return AppCompatActivity if it's not null
*/
public static AppCompatActivity getAppCompActivity(Context context) {
if (context == null) return null;
if (context instanceof AppCompatActivity) {
return (AppCompatActivity) context;
} else if (context instanceof ContextThemeWrapper) {
return getAppCompActivity(((ContextThemeWrapper) context).getBaseContext());
}
return null;
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public static void saveProgress(Context context, String url, int progress) {
if (!JCVideoPlayer.SAVE_PROGRESS) return;
SharedPreferences spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = spn.edit();
editor.putInt(url, progress);
editor.apply();
}
public static int getSavedProgress(Context context, String url) {
if (!JCVideoPlayer.SAVE_PROGRESS) return 0;
SharedPreferences spn;
spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
return spn.getInt(url, 0);
}
/**
* if url == null, clear all progress
*
* @param context
* @param url if url!=null clear this url progress
*/
public static void clearSavedProgress(Context context, String url) {
if (TextUtils.isEmpty(url)) {
SharedPreferences spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
spn.edit().clear().apply();
} else {
SharedPreferences spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
spn.edit().putInt(url, 0).apply();
}
}
}

View File

@ -0,0 +1,954 @@
package fm.jiecao.jcvideoplayer_lib;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.provider.Settings;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by Nathen on 16/7/30.
*/
public abstract class JCVideoPlayer extends FrameLayout implements View.OnClickListener, SeekBar.OnSeekBarChangeListener, View.OnTouchListener {
public static final String TAG = "JieCaoVideoPlayer";
public static boolean ACTION_BAR_EXIST = true;
public static boolean TOOL_BAR_EXIST = true;
public static int FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
public static int NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
public static boolean SAVE_PROGRESS = true;
public static boolean WIFI_TIP_DIALOG_SHOWED = false;
public static final int FULLSCREEN_ID = 33797;
public static final int TINY_ID = 33798;
public static final int THRESHOLD = 80;
public static final int FULL_SCREEN_NORMAL_DELAY = 300;
public static long CLICK_QUIT_FULLSCREEN_TIME = 0;
public static final int SCREEN_LAYOUT_NORMAL = 0;
public static final int SCREEN_LAYOUT_LIST = 1;
public static final int SCREEN_WINDOW_FULLSCREEN = 2;
public static final int SCREEN_WINDOW_TINY = 3;
public static final int CURRENT_STATE_NORMAL = 0;
public static final int CURRENT_STATE_PREPARING = 1;
public static final int CURRENT_STATE_PLAYING = 2;
public static final int CURRENT_STATE_PLAYING_BUFFERING_START = 3;
public static final int CURRENT_STATE_PAUSE = 5;
public static final int CURRENT_STATE_AUTO_COMPLETE = 6;
public static final int CURRENT_STATE_ERROR = 7;
public static int BACKUP_PLAYING_BUFFERING_STATE = -1;
public int currentState = -1;
public int currentScreen = -1;
public boolean loop = false;
public Map<String, String> headData;
public String url = "";
public Object[] objects = null;
public int seekToInAdvance = 0;
public ImageView startButton;
public SeekBar progressBar;
public ImageView fullscreenButton;
public TextView currentTimeTextView, totalTimeTextView;
public ViewGroup textureViewContainer;
public ViewGroup topContainer, bottomContainer;
protected static JCUserAction JC_USER_EVENT;
protected static Timer UPDATE_PROGRESS_TIMER;
protected int mScreenWidth;
protected int mScreenHeight;
protected AudioManager mAudioManager;
protected Handler mHandler;
protected ProgressTimerTask mProgressTimerTask;
protected boolean mTouchingProgressBar;
protected float mDownX;
protected float mDownY;
protected boolean mChangeVolume;
protected boolean mChangePosition;
protected boolean mChangeBrightness;
protected int mGestureDownPosition;
protected int mGestureDownVolume;
protected float mGestureDownBrightness;
protected int mSeekTimePosition;
public JCVideoPlayer(Context context) {
super(context);
init(context);
}
public JCVideoPlayer(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public void init(Context context) {
View.inflate(context, getLayoutId(), this);
startButton = (ImageView) findViewById(R.id.start);
fullscreenButton = (ImageView) findViewById(R.id.fullscreen);
progressBar = (SeekBar) findViewById(R.id.bottom_seek_progress);
currentTimeTextView = (TextView) findViewById(R.id.current);
totalTimeTextView = (TextView) findViewById(R.id.total);
bottomContainer = (ViewGroup) findViewById(R.id.layout_bottom);
textureViewContainer = (ViewGroup) findViewById(R.id.surface_container);
topContainer = (ViewGroup) findViewById(R.id.layout_top);
startButton.setOnClickListener(this);
fullscreenButton.setOnClickListener(this);
progressBar.setOnSeekBarChangeListener(this);
bottomContainer.setOnClickListener(this);
textureViewContainer.setOnClickListener(this);
textureViewContainer.setOnTouchListener(this);
mScreenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
mScreenHeight = getContext().getResources().getDisplayMetrics().heightPixels;
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mHandler = new Handler();
}
public void setUp(String url, int screen, Object... objects) {
if (!TextUtils.isEmpty(this.url) && TextUtils.equals(this.url, url)) {
return;
}
this.url = url;
this.objects = objects;
this.currentScreen = screen;
this.headData = null;
setUiWitStateAndScreen(CURRENT_STATE_NORMAL);
}
@Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.start) {
Log.i(TAG, "onClick start [" + this.hashCode() + "] ");
if (TextUtils.isEmpty(url)) {
Toast.makeText(getContext(), getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show();
return;
}
if (currentState == CURRENT_STATE_NORMAL || currentState == CURRENT_STATE_ERROR) {
if (!url.startsWith("file") && !JCUtils.isWifiConnected(getContext()) && !WIFI_TIP_DIALOG_SHOWED) {
showWifiDialog();
return;
}
prepareMediaPlayer();
onEvent(currentState != CURRENT_STATE_ERROR ? JCUserAction.ON_CLICK_START_ICON : JCUserAction.ON_CLICK_START_ERROR);
} else if (currentState == CURRENT_STATE_PLAYING) {
onEvent(JCUserAction.ON_CLICK_PAUSE);
Log.d(TAG, "pauseVideo [" + this.hashCode() + "] ");
JCMediaManager.instance().mediaPlayer.pause();
setUiWitStateAndScreen(CURRENT_STATE_PAUSE);
} else if (currentState == CURRENT_STATE_PAUSE) {
onEvent(JCUserAction.ON_CLICK_RESUME);
JCMediaManager.instance().mediaPlayer.start();
setUiWitStateAndScreen(CURRENT_STATE_PLAYING);
} else if (currentState == CURRENT_STATE_AUTO_COMPLETE) {
onEvent(JCUserAction.ON_CLICK_START_AUTO_COMPLETE);
prepareMediaPlayer();
}
} else if (i == R.id.fullscreen) {
Log.i(TAG, "onClick fullscreen [" + this.hashCode() + "] ");
if (currentState == CURRENT_STATE_AUTO_COMPLETE) return;
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
//quit fullscreen
backPress();
} else {
Log.d(TAG, "toFullscreenActivity [" + this.hashCode() + "] ");
onEvent(JCUserAction.ON_ENTER_FULLSCREEN);
startWindowFullscreen();
}
} else if (i == R.id.surface_container && currentState == CURRENT_STATE_ERROR) {
Log.i(TAG, "onClick surfaceContainer State=Error [" + this.hashCode() + "] ");
prepareMediaPlayer();
}
}
public void prepareMediaPlayer() {
JCVideoPlayerManager.completeAll();
Log.d(TAG, "prepareMediaPlayer [" + this.hashCode() + "] ");
initTextureView();
addTextureView();
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
JCUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
JCMediaManager.CURRENT_PLAYING_URL = url;
JCMediaManager.CURRENT_PLING_LOOP = loop;
JCMediaManager.MAP_HEADER_DATA = headData;
setUiWitStateAndScreen(CURRENT_STATE_PREPARING);
JCVideoPlayerManager.setFirstFloor(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
int id = v.getId();
if (id == R.id.surface_container) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onTouch surfaceContainer actionDown [" + this.hashCode() + "] ");
mTouchingProgressBar = true;
mDownX = x;
mDownY = y;
mChangeVolume = false;
mChangePosition = false;
mChangeBrightness = false;
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onTouch surfaceContainer actionMove [" + this.hashCode() + "] ");
float deltaX = x - mDownX;
float deltaY = y - mDownY;
float absDeltaX = Math.abs(deltaX);
float absDeltaY = Math.abs(deltaY);
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
if (!mChangePosition && !mChangeVolume && !mChangeBrightness) {
if (absDeltaX > THRESHOLD || absDeltaY > THRESHOLD) {
cancelProgressTimer();
if (absDeltaX >= THRESHOLD) {
// 全屏模式下的CURRENT_STATE_ERROR状态下,不响应进度拖动事件.
// 否则会因为mediaplayer的状态非法导致App Crash
if (currentState != CURRENT_STATE_ERROR) {
mChangePosition = true;
mGestureDownPosition = getCurrentPositionWhenPlaying();
}
} else {
//如果y轴滑动距离超过设置的处理范围那么进行滑动事件处理
if (mDownX < mScreenWidth * 0.5f) {//左侧改变亮度
mChangeBrightness = true;
// WindowManager.LayoutParams lp = JCUtils.getAppCompActivity(getContext()).getWindow().getAttributes();
// if (lp.screenBrightness < 0) {
// try {
// mGestureDownBrightness = Settings.System.getInt(getContext().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
// Log.i(TAG, "current system brightness: " + mGestureDownBrightness);
// } catch (Settings.SettingNotFoundException e) {
// e.printStackTrace();
// }
// } else {
// mGestureDownBrightness = lp.screenBrightness * 255;
// Log.i(TAG, "current activity brightness: " + mGestureDownBrightness);
// }
} else {//右侧改变声音
mChangeVolume = true;
mGestureDownVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
}
}
}
}
}
if (mChangePosition) {
int totalTimeDuration = getDuration();
mSeekTimePosition = (int) (mGestureDownPosition + deltaX * totalTimeDuration / mScreenWidth);
if (mSeekTimePosition > totalTimeDuration)
mSeekTimePosition = totalTimeDuration;
String seekTime = JCUtils.stringForTime(mSeekTimePosition);
String totalTime = JCUtils.stringForTime(totalTimeDuration);
showProgressDialog(deltaX, seekTime, mSeekTimePosition, totalTime, totalTimeDuration);
}
if (mChangeVolume) {
deltaY = -deltaY;
int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
int deltaV = (int) (max * deltaY * 3 / mScreenHeight);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mGestureDownVolume + deltaV, 0);
//dialog中显示百分比
int volumePercent = (int) (mGestureDownVolume * 100 / max + deltaY * 3 * 100 / mScreenHeight);
showVolumeDialog(-deltaY, volumePercent);
}
if (mChangeBrightness) {
deltaY = -deltaY;
int deltaV = (int) (255 * deltaY * 3 / mScreenHeight);
// WindowManager.LayoutParams params = JCUtils.getAppCompActivity(getContext()).getWindow().getAttributes();
if (((mGestureDownBrightness + deltaV) / 255) >= 1) {//这和声音有区别必须自己过滤一下负值
// params.screenBrightness = 1;
} else if (((mGestureDownBrightness + deltaV) / 255) <= 0) {
// params.screenBrightness = 0.01f;
} else {
// params.screenBrightness = (mGestureDownBrightness + deltaV) / 255;
}
// JCUtils.getAppCompActivity(getContext()).getWindow().setAttributes(params);
//dialog中显示百分比
int brightnessPercent = (int) (mGestureDownBrightness * 100 / 255 + deltaY * 3 * 100 / mScreenHeight);
showBrightnessDialog(brightnessPercent);
// mDownY = y;
}
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onTouch surfaceContainer actionUp [" + this.hashCode() + "] ");
mTouchingProgressBar = false;
dismissProgressDialog();
dismissVolumeDialog();
dismissBrightnessDialog();
if (mChangePosition) {
onEvent(JCUserAction.ON_TOUCH_SCREEN_SEEK_POSITION);
JCMediaManager.instance().mediaPlayer.seekTo(mSeekTimePosition);
int duration = getDuration();
int progress = mSeekTimePosition * 100 / (duration == 0 ? 1 : duration);
progressBar.setProgress(progress);
}
if (mChangeVolume) {
onEvent(JCUserAction.ON_TOUCH_SCREEN_SEEK_VOLUME);
}
startProgressTimer();
break;
}
}
return false;
}
public int widthRatio = 0;
public int heightRatio = 0;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (currentScreen == SCREEN_WINDOW_FULLSCREEN || currentScreen == SCREEN_WINDOW_TINY) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
if (widthRatio != 0 && heightRatio != 0) {
int specWidth = MeasureSpec.getSize(widthMeasureSpec);
int specHeight = (int) ((specWidth * (float) heightRatio) / widthRatio);
setMeasuredDimension(specWidth, specHeight);
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(specWidth, MeasureSpec.EXACTLY);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.EXACTLY);
getChildAt(0).measure(childWidthMeasureSpec, childHeightMeasureSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void initTextureView() {
removeTextureView();
JCMediaManager.textureView = new JCResizeTextureView(getContext());
JCMediaManager.textureView.setSurfaceTextureListener(JCMediaManager.instance());
}
public void addTextureView() {
Log.d(TAG, "addTextureView [" + this.hashCode() + "] ");
FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
Gravity.CENTER);
textureViewContainer.addView(JCMediaManager.textureView, layoutParams);
}
public void removeTextureView() {
JCMediaManager.savedSurfaceTexture = null;
if (JCMediaManager.textureView != null && JCMediaManager.textureView.getParent() != null) {
((ViewGroup) JCMediaManager.textureView.getParent()).removeView(JCMediaManager.textureView);
}
}
public void setUiWitStateAndScreen(int state) {
currentState = state;
switch (currentState) {
case CURRENT_STATE_NORMAL:
cancelProgressTimer();
if (isCurrentJcvd()) {//这个if是无法取代的否则进入全屏的时候会releaseMediaPlayer
JCMediaManager.instance().releaseMediaPlayer();
}
break;
case CURRENT_STATE_PREPARING:
resetProgressAndTime();
break;
case CURRENT_STATE_PLAYING:
case CURRENT_STATE_PAUSE:
case CURRENT_STATE_PLAYING_BUFFERING_START:
startProgressTimer();
break;
case CURRENT_STATE_ERROR:
cancelProgressTimer();
break;
case CURRENT_STATE_AUTO_COMPLETE:
cancelProgressTimer();
progressBar.setProgress(100);
currentTimeTextView.setText(totalTimeTextView.getText());
break;
}
}
public void startProgressTimer() {
cancelProgressTimer();
UPDATE_PROGRESS_TIMER = new Timer();
mProgressTimerTask = new ProgressTimerTask();
UPDATE_PROGRESS_TIMER.schedule(mProgressTimerTask, 0, 300);
}
public void cancelProgressTimer() {
if (UPDATE_PROGRESS_TIMER != null) {
UPDATE_PROGRESS_TIMER.cancel();
}
if (mProgressTimerTask != null) {
mProgressTimerTask.cancel();
}
}
public void onPrepared() {
Log.i(TAG, "onPrepared " + " [" + this.hashCode() + "] ");
if (currentState != CURRENT_STATE_PREPARING) return;
if (seekToInAdvance != 0) {
JCMediaManager.instance().mediaPlayer.seekTo(seekToInAdvance);
seekToInAdvance = 0;
} else {
int position = JCUtils.getSavedProgress(getContext(), url);
if (position != 0) {
JCMediaManager.instance().mediaPlayer.seekTo(position);
}
}
startProgressTimer();
setUiWitStateAndScreen(CURRENT_STATE_PLAYING);
}
public void clearFullscreenLayout() {
ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView();
.findViewById(Window.ID_ANDROID_CONTENT);
View oldF = vp.findViewById(FULLSCREEN_ID);
View oldT = vp.findViewById(TINY_ID);
if (oldF != null) {
vp.removeView(oldF);
}
if (oldT != null) {
vp.removeView(oldT);
}
showSupportActionBar(getContext());
}
public void onAutoCompletion() {
//加上这句避免循环播放video的时候内存不断飙升
Runtime.getRuntime().gc();
Log.i(TAG, "onAutoCompletion " + " [" + this.hashCode() + "] ");
onEvent(JCUserAction.ON_AUTO_COMPLETE);
dismissVolumeDialog();
dismissProgressDialog();
dismissBrightnessDialog();
cancelProgressTimer();
setUiWitStateAndScreen(CURRENT_STATE_AUTO_COMPLETE);
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
backPress();
}
JCUtils.saveProgress(getContext(), url, 0);
}
public void onCompletion() {
Log.i(TAG, "onCompletion " + " [" + this.hashCode() + "] ");
//save position
if (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE) {
int position = getCurrentPositionWhenPlaying();
// int duration = getDuration();
JCUtils.saveProgress(getContext(), url, position);
}
cancelProgressTimer();
setUiWitStateAndScreen(CURRENT_STATE_NORMAL);
// 清理缓存变量
textureViewContainer.removeView(JCMediaManager.textureView);
JCMediaManager.instance().currentVideoWidth = 0;
JCMediaManager.instance().currentVideoHeight = 0;
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
JCUtils.scanForActivity(getContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
clearFullscreenLayout();
// JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(NORMAL_ORIENTATION);
JCMediaManager.textureView = null;
JCMediaManager.savedSurfaceTexture = null;
}
//退出全屏和小窗的方法
public void playOnThisJcvd() {
Log.i(TAG, "playOnThisJcvd " + " [" + this.hashCode() + "] ");
//1.清空全屏和小窗的jcvd
currentState = JCVideoPlayerManager.getSecondFloor().currentState;
clearFloatScreen();
//2.在本jcvd上播放
setUiWitStateAndScreen(currentState);
addTextureView();
}
public void clearFloatScreen() {
// JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(NORMAL_ORIENTATION);
showSupportActionBar(getContext());
JCVideoPlayer currJcvd = JCVideoPlayerManager.getCurrentJcvd();
currJcvd.textureViewContainer.removeView(JCMediaManager.textureView);
ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView();
.findViewById(Window.ID_ANDROID_CONTENT);
vp.removeView(currJcvd);
JCVideoPlayerManager.setSecondFloor(null);
}
public static long lastAutoFullscreenTime = 0;
//重力感应的时候调用的函数
public void autoFullscreen(float x) {
if (isCurrentJcvd()
&& currentState == CURRENT_STATE_PLAYING
&& currentScreen != SCREEN_WINDOW_FULLSCREEN
&& currentScreen != SCREEN_WINDOW_TINY) {
if (x > 0) {
// JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(
// ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
// JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(
// ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
}
startWindowFullscreen();
}
}
public void autoQuitFullscreen() {
if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000
&& isCurrentJcvd()
&& currentState == CURRENT_STATE_PLAYING
&& currentScreen == SCREEN_WINDOW_FULLSCREEN) {
lastAutoFullscreenTime = System.currentTimeMillis();
backPress();
}
}
public void onSeekComplete() {
}
public void onError(int what, int extra) {
Log.e(TAG, "onError " + what + " - " + extra + " [" + this.hashCode() + "] ");
if (what != 38 && what != -38) {
setUiWitStateAndScreen(CURRENT_STATE_ERROR);
if (isCurrentJcvd()) {
JCMediaManager.instance().releaseMediaPlayer();
}
}
}
public void onInfo(int what, int extra) {
Log.d(TAG, "onInfo what - " + what + " extra - " + extra);
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
if (currentState == CURRENT_STATE_PLAYING_BUFFERING_START) return;
BACKUP_PLAYING_BUFFERING_STATE = currentState;
setUiWitStateAndScreen(CURRENT_STATE_PLAYING_BUFFERING_START);//没这个case
Log.d(TAG, "MEDIA_INFO_BUFFERING_START");
} else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
if (BACKUP_PLAYING_BUFFERING_STATE != -1) {
setUiWitStateAndScreen(BACKUP_PLAYING_BUFFERING_STATE);
BACKUP_PLAYING_BUFFERING_STATE = -1;
}
Log.d(TAG, "MEDIA_INFO_BUFFERING_END");
}
}
public void onVideoSizeChanged() {
Log.i(TAG, "onVideoSizeChanged " + " [" + this.hashCode() + "] ");
if (JCMediaManager.textureView != null) {
JCMediaManager.textureView.setVideoSize(JCMediaManager.instance().getVideoSize());
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
Log.i(TAG, "bottomProgress onStartTrackingTouch [" + this.hashCode() + "] ");
cancelProgressTimer();
ViewParent vpdown = getParent();
while (vpdown != null) {
vpdown.requestDisallowInterceptTouchEvent(true);
vpdown = vpdown.getParent();
}
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
Log.i(TAG, "bottomProgress onStopTrackingTouch [" + this.hashCode() + "] ");
onEvent(JCUserAction.ON_SEEK_POSITION);
startProgressTimer();
ViewParent vpup = getParent();
while (vpup != null) {
vpup.requestDisallowInterceptTouchEvent(false);
vpup = vpup.getParent();
}
if (currentState != CURRENT_STATE_PLAYING &&
currentState != CURRENT_STATE_PAUSE) return;
int time = seekBar.getProgress() * getDuration() / 100;
JCMediaManager.instance().mediaPlayer.seekTo(time);
Log.i(TAG, "seekTo " + time + " [" + this.hashCode() + "] ");
}
public static boolean backPress() {
Log.i(TAG, "backPress");
if ((System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) < FULL_SCREEN_NORMAL_DELAY)
return false;
if (JCVideoPlayerManager.getSecondFloor() != null) {
CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis();
JCVideoPlayer jcVideoPlayer = JCVideoPlayerManager.getSecondFloor();
jcVideoPlayer.onEvent(jcVideoPlayer.currentScreen == JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN ?
JCUserAction.ON_QUIT_FULLSCREEN :
JCUserAction.ON_QUIT_TINYSCREEN);
JCVideoPlayerManager.getFirstFloor().playOnThisJcvd();
return true;
} else if (JCVideoPlayerManager.getFirstFloor() != null &&
(JCVideoPlayerManager.getFirstFloor().currentScreen == SCREEN_WINDOW_FULLSCREEN ||
JCVideoPlayerManager.getFirstFloor().currentScreen == SCREEN_WINDOW_TINY)) {//以前我总想把这两个判断写到一起这分明是两个独立是逻辑
CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis();
//直接退出全屏和小窗
JCVideoPlayerManager.getCurrentJcvd().currentState = CURRENT_STATE_NORMAL;
JCVideoPlayerManager.getFirstFloor().clearFloatScreen();
JCMediaManager.instance().releaseMediaPlayer();
JCVideoPlayerManager.setFirstFloor(null);
return true;
}
return false;
}
public void startWindowFullscreen() {
Log.i(TAG, "startWindowFullscreen " + " [" + this.hashCode() + "] ");
hideSupportActionBar(getContext());
// JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(FULLSCREEN_ORIENTATION);
ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView();
.findViewById(Window.ID_ANDROID_CONTENT);
View old = vp.findViewById(FULLSCREEN_ID);
if (old != null) {
vp.removeView(old);
}
// ((ViewGroup)JCMediaManager.textureView.getParent()).removeView(JCMediaManager.textureView);
textureViewContainer.removeView(JCMediaManager.textureView);
try {
Constructor<JCVideoPlayer> constructor = (Constructor<JCVideoPlayer>) JCVideoPlayer.this.getClass().getConstructor(Context.class);
JCVideoPlayer jcVideoPlayer = constructor.newInstance(getContext());
jcVideoPlayer.setId(FULLSCREEN_ID);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
vp.addView(jcVideoPlayer, lp);
jcVideoPlayer.setUp(url, JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN, objects);
jcVideoPlayer.setUiWitStateAndScreen(currentState);
jcVideoPlayer.addTextureView();
JCVideoPlayerManager.setSecondFloor(jcVideoPlayer);
// final Animation ra = AnimationUtils.loadAnimation(getContext(), R.anim.start_fullscreen);
// jcVideoPlayer.setAnimation(ra);
CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis();
} catch (Exception e) {
e.printStackTrace();
}
}
public void startWindowTiny() {
Log.i(TAG, "startWindowTiny " + " [" + this.hashCode() + "] ");
onEvent(JCUserAction.ON_ENTER_TINYSCREEN);
if (currentState == CURRENT_STATE_NORMAL || currentState == CURRENT_STATE_ERROR) return;
ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView();
.findViewById(Window.ID_ANDROID_CONTENT);
View old = vp.findViewById(TINY_ID);
if (old != null) {
vp.removeView(old);
}
textureViewContainer.removeView(JCMediaManager.textureView);
try {
Constructor<JCVideoPlayer> constructor = (Constructor<JCVideoPlayer>) JCVideoPlayer.this.getClass().getConstructor(Context.class);
JCVideoPlayer jcVideoPlayer = constructor.newInstance(getContext());
jcVideoPlayer.setId(TINY_ID);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(400, 400);
lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
vp.addView(jcVideoPlayer, lp);
jcVideoPlayer.setUp(url, JCVideoPlayerStandard.SCREEN_WINDOW_TINY, objects);
jcVideoPlayer.setUiWitStateAndScreen(currentState);
jcVideoPlayer.addTextureView();
JCVideoPlayerManager.setSecondFloor(jcVideoPlayer);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public class ProgressTimerTask extends TimerTask {
@Override
public void run() {
if (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE || currentState == CURRENT_STATE_PLAYING_BUFFERING_START) {
// Log.v(TAG, "onProgressUpdate " + position + "/" + duration + " [" + this.hashCode() + "] ");
mHandler.post(new Runnable() {
@Override
public void run() {
setProgressAndText();
}
});
}
}
}
public int getCurrentPositionWhenPlaying() {
int position = 0;
if (JCMediaManager.instance().mediaPlayer == null)
return position;//这行代码不应该在这如果代码和逻辑万无一失的话心头之恨呐
if (currentState == CURRENT_STATE_PLAYING ||
currentState == CURRENT_STATE_PAUSE ||
currentState == CURRENT_STATE_PLAYING_BUFFERING_START) {
try {
position = JCMediaManager.instance().mediaPlayer.getCurrentPosition();
} catch (IllegalStateException e) {
e.printStackTrace();
return position;
}
}
return position;
}
public int getDuration() {
int duration = 0;
if (JCMediaManager.instance().mediaPlayer == null) return duration;
try {
duration = JCMediaManager.instance().mediaPlayer.getDuration();
} catch (IllegalStateException e) {
e.printStackTrace();
return duration;
}
return duration;
}
public void setProgressAndText() {
int position = getCurrentPositionWhenPlaying();
int duration = getDuration();
int progress = position * 100 / (duration == 0 ? 1 : duration);
if (!mTouchingProgressBar) {
if (progress != 0) progressBar.setProgress(progress);
}
if (position != 0) currentTimeTextView.setText(JCUtils.stringForTime(position));
totalTimeTextView.setText(JCUtils.stringForTime(duration));
}
public void setBufferProgress(int bufferProgress) {
if (bufferProgress != 0) progressBar.setSecondaryProgress(bufferProgress);
}
public void resetProgressAndTime() {
progressBar.setProgress(0);
progressBar.setSecondaryProgress(0);
currentTimeTextView.setText(JCUtils.stringForTime(0));
totalTimeTextView.setText(JCUtils.stringForTime(0));
}
public static AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
break;
case AudioManager.AUDIOFOCUS_LOSS:
releaseAllVideos();
Log.d(TAG, "AUDIOFOCUS_LOSS [" + this.hashCode() + "]");
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
try {
if (JCMediaManager.instance().mediaPlayer != null &&
JCMediaManager.instance().mediaPlayer.isPlaying()) {
JCMediaManager.instance().mediaPlayer.pause();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT [" + this.hashCode() + "]");
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
break;
}
}
};
public void release() {
if (url.equals(JCMediaManager.CURRENT_PLAYING_URL) &&
(System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) > FULL_SCREEN_NORMAL_DELAY) {
//在非全屏的情况下只能backPress()
if (JCVideoPlayerManager.getSecondFloor() != null &&
JCVideoPlayerManager.getSecondFloor().currentScreen == SCREEN_WINDOW_FULLSCREEN) {//点击全屏
} else if (JCVideoPlayerManager.getSecondFloor() == null && JCVideoPlayerManager.getFirstFloor() != null &&
JCVideoPlayerManager.getFirstFloor().currentScreen == SCREEN_WINDOW_FULLSCREEN) {//直接全屏
} else {
Log.d(TAG, "release [" + this.hashCode() + "]");
releaseAllVideos();
}
}
}
//isCurrentJcvd and isCurrenPlayUrl should be two logic methods,isCurrentJcvd is for different jcvd with same
//url when fullscreen or tiny screen. isCurrenPlayUrl is to find where is myself when back from tiny screen.
//Sometimes they are overlap.
public boolean isCurrentJcvd() {//虽然看这个函数很不爽但是干不掉
return JCVideoPlayerManager.getCurrentJcvd() != null
&& JCVideoPlayerManager.getCurrentJcvd() == this;
}
// public boolean isCurrenPlayingUrl() {
// return url.equals(JCMediaManager.CURRENT_PLAYING_URL);
// }
public static void releaseAllVideos() {
if ((System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) > FULL_SCREEN_NORMAL_DELAY) {
Log.d(TAG, "releaseAllVideos");
JCVideoPlayerManager.completeAll();
JCMediaManager.instance().releaseMediaPlayer();
}
}
public static void setJcUserAction(JCUserAction jcUserEvent) {
JC_USER_EVENT = jcUserEvent;
}
public void onEvent(int type) {
if (JC_USER_EVENT != null && isCurrentJcvd()) {
JC_USER_EVENT.onEvent(type, url, currentScreen, objects);
}
}
public static void startFullscreen(Context context, Class _class, String url, Object... objects) {
hideSupportActionBar(context);
// JCUtils.getAppCompActivity(context).setRequestedOrientation(FULLSCREEN_ORIENTATION);
ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(context))//.getWindow().getDecorView();
.findViewById(Window.ID_ANDROID_CONTENT);
View old = vp.findViewById(JCVideoPlayer.FULLSCREEN_ID);
if (old != null) {
vp.removeView(old);
}
try {
Constructor<JCVideoPlayer> constructor = _class.getConstructor(Context.class);
final JCVideoPlayer jcVideoPlayer = constructor.newInstance(context);
jcVideoPlayer.setId(JCVideoPlayer.FULLSCREEN_ID);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
vp.addView(jcVideoPlayer, lp);
// final Animation ra = AnimationUtils.loadAnimation(context, R.anim.start_fullscreen);
// jcVideoPlayer.setAnimation(ra);
jcVideoPlayer.setUp(url, JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN, objects);
CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis();
jcVideoPlayer.startButton.performClick();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void hideSupportActionBar(Context context) {
if (ACTION_BAR_EXIST) {
// ActionBar ab = JCUtils.getAppCompActivity(context).getSupportActionBar();
// if (ab != null) {
// ab.setShowHideAnimationEnabled(false);
// ab.hide();
// }
}
if (TOOL_BAR_EXIST) {
// JCUtils.getAppCompActivity(context).getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
// WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
public static void showSupportActionBar(Context context) {
if (ACTION_BAR_EXIST) {
// ActionBar ab = JCUtils.getAppCompActivity(context).getSupportActionBar();
// if (ab != null) {
// ab.setShowHideAnimationEnabled(false);
// ab.show();
// }
}
if (TOOL_BAR_EXIST) {
// JCUtils.getAppCompActivity(context).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
public static class JCAutoFullscreenListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {//可以得到传感器实时测量出来的变化值
final float x = event.values[SensorManager.DATA_X];
float y = event.values[SensorManager.DATA_Y];
float z = event.values[SensorManager.DATA_Z];
//过滤掉用力过猛会有一个反向的大数值
if (((x > -15 && x < -10) || (x < 15 && x > 10)) && Math.abs(y) < 1.5) {
if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000) {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().autoFullscreen(x);
}
lastAutoFullscreenTime = System.currentTimeMillis();
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
public static void clearSavedProgress(Context context, String url) {
JCUtils.clearSavedProgress(context, url);
}
public void showWifiDialog() {
}
public void showProgressDialog(float deltaX,
String seekTime, int seekTimePosition,
String totalTime, int totalTimeDuration) {
}
public void dismissProgressDialog() {
}
public void showVolumeDialog(float deltaY, int volumePercent) {
}
public void dismissVolumeDialog() {
}
public void showBrightnessDialog(int brightnessPercent) {
}
public void dismissBrightnessDialog() {
}
public abstract int getLayoutId();
}

View File

@ -0,0 +1,46 @@
package fm.jiecao.jcvideoplayer_lib;
/**
* Put JCVideoPlayer into layout
* From a JCVideoPlayer to another JCVideoPlayer
* Created by Nathen on 16/7/26.
*/
public class JCVideoPlayerManager {
public static JCVideoPlayer FIRST_FLOOR_JCVD;
public static JCVideoPlayer SECOND_FLOOR_JCVD;
public static void setFirstFloor(JCVideoPlayer jcVideoPlayer) {
FIRST_FLOOR_JCVD = jcVideoPlayer;
}
public static void setSecondFloor(JCVideoPlayer jcVideoPlayer) {
SECOND_FLOOR_JCVD = jcVideoPlayer;
}
public static JCVideoPlayer getFirstFloor() {
return FIRST_FLOOR_JCVD;
}
public static JCVideoPlayer getSecondFloor() {
return SECOND_FLOOR_JCVD;
}
public static JCVideoPlayer getCurrentJcvd() {
if (getSecondFloor() != null) {
return getSecondFloor();
}
return getFirstFloor();
}
public static void completeAll() {
if (SECOND_FLOOR_JCVD != null) {
SECOND_FLOOR_JCVD.onCompletion();
SECOND_FLOOR_JCVD = null;
}
if (FIRST_FLOOR_JCVD != null) {
FIRST_FLOOR_JCVD.onCompletion();
FIRST_FLOOR_JCVD = null;
}
}
}

View File

@ -0,0 +1,94 @@
package fm.jiecao.jcvideoplayer_lib;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.SeekBar;
import android.widget.Toast;
/**
* Manage UI
* Created by Nathen
* On 2016/04/10 15:45
*/
public class JCVideoPlayerSimple extends JCVideoPlayer {
public JCVideoPlayerSimple(Context context) {
super(context);
}
public JCVideoPlayerSimple(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public int getLayoutId() {
return R.layout.jc_layout_base;
}
@Override
public void setUp(String url, int screen, Object... objects) {
super.setUp(url, screen, objects);
updateFullscreenButton();
fullscreenButton.setVisibility(View.GONE);
}
@Override
public void setUiWitStateAndScreen(int state) {
super.setUiWitStateAndScreen(state);
switch (currentState) {
case CURRENT_STATE_NORMAL:
startButton.setVisibility(View.VISIBLE);
break;
case CURRENT_STATE_PREPARING:
startButton.setVisibility(View.INVISIBLE);
break;
case CURRENT_STATE_PLAYING:
startButton.setVisibility(View.VISIBLE);
break;
case CURRENT_STATE_PAUSE:
break;
case CURRENT_STATE_ERROR:
break;
}
updateStartImage();
}
private void updateStartImage() {
if (currentState == CURRENT_STATE_PLAYING) {
startButton.setImageResource(R.drawable.jc_click_pause_selector);
} else if (currentState == CURRENT_STATE_ERROR) {
startButton.setImageResource(R.drawable.jc_click_error_selector);
} else {
startButton.setImageResource(R.drawable.jc_click_play_selector);
}
}
public void updateFullscreenButton() {
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
fullscreenButton.setImageResource(R.drawable.jc_shrink);
} else {
fullscreenButton.setImageResource(R.drawable.jc_enlarge);
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.fullscreen && currentState == CURRENT_STATE_NORMAL) {
Toast.makeText(getContext(), "Play video first", Toast.LENGTH_SHORT).show();
return;
}
super.onClick(v);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
if (currentState == CURRENT_STATE_NORMAL) {
Toast.makeText(getContext(), "Play video first", Toast.LENGTH_SHORT).show();
return;
}
}
super.onProgressChanged(seekBar, progress, fromUser);
}
}

View File

@ -0,0 +1,785 @@
package fm.jiecao.jcvideoplayer_lib;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by Nathen
* On 2016/04/18 16:15
*/
public class JCVideoPlayerStandard extends JCVideoPlayer {
protected static Timer DISMISS_CONTROL_VIEW_TIMER;
public ImageView backButton;
public ProgressBar bottomProgressBar, loadingProgressBar;
public TextView titleTextView;
public ImageView thumbImageView;
public ImageView tinyBackImageView;
protected DismissControlViewTimerTask mDismissControlViewTimerTask;
public JCVideoPlayerStandard(Context context) {
super(context);
}
public JCVideoPlayerStandard(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void init(Context context) {
super.init(context);
bottomProgressBar = (ProgressBar) findViewById(R.id.bottom_progress);
titleTextView = (TextView) findViewById(R.id.title);
backButton = (ImageView) findViewById(R.id.back);
thumbImageView = (ImageView) findViewById(R.id.thumb);
loadingProgressBar = (ProgressBar) findViewById(R.id.loading);
tinyBackImageView = (ImageView) findViewById(R.id.back_tiny);
thumbImageView.setOnClickListener(this);
backButton.setOnClickListener(this);
tinyBackImageView.setOnClickListener(this);
}
@Override
public void setUp(String url, int screen, Object... objects) {
super.setUp(url, screen, objects);
if (objects.length == 0) return;
titleTextView.setText(objects[0].toString());
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
fullscreenButton.setImageResource(R.drawable.jc_shrink);
backButton.setVisibility(View.VISIBLE);
tinyBackImageView.setVisibility(View.INVISIBLE);
changeStartButtonSize((int) getResources().getDimension(R.dimen.jc_start_button_w_h_fullscreen));
} else if (currentScreen == SCREEN_LAYOUT_NORMAL
|| currentScreen == SCREEN_LAYOUT_LIST) {
fullscreenButton.setImageResource(R.drawable.jc_enlarge);
backButton.setVisibility(View.GONE);
tinyBackImageView.setVisibility(View.INVISIBLE);
changeStartButtonSize((int) getResources().getDimension(R.dimen.jc_start_button_w_h_normal));
} else if (currentScreen == SCREEN_WINDOW_TINY) {
tinyBackImageView.setVisibility(View.VISIBLE);
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
}
fullscreenButton.setVisibility(GONE);
}
public void changeStartButtonSize(int size) {
ViewGroup.LayoutParams lp = startButton.getLayoutParams();
lp.height = size;
lp.width = size;
lp = loadingProgressBar.getLayoutParams();
lp.height = size;
lp.width = size;
}
@Override
public int getLayoutId() {
return R.layout.jc_layout_standard;
}
@Override
public void setUiWitStateAndScreen(int state) {
super.setUiWitStateAndScreen(state);
switch (currentState) {
case CURRENT_STATE_NORMAL:
changeUiToNormal();
break;
case CURRENT_STATE_PREPARING:
changeUiToPreparingShow();
startDismissControlViewTimer();
break;
case CURRENT_STATE_PLAYING:
changeUiToPlayingShow();
startDismissControlViewTimer();
break;
case CURRENT_STATE_PAUSE:
changeUiToPauseShow();
cancelDismissControlViewTimer();
break;
case CURRENT_STATE_ERROR:
changeUiToError();
break;
case CURRENT_STATE_AUTO_COMPLETE:
changeUiToCompleteShow();
cancelDismissControlViewTimer();
bottomProgressBar.setProgress(100);
break;
case CURRENT_STATE_PLAYING_BUFFERING_START:
changeUiToPlayingBufferingShow();
break;
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int id = v.getId();
if (id == R.id.surface_container) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
startDismissControlViewTimer();
if (mChangePosition) {
int duration = getDuration();
int progress = mSeekTimePosition * 100 / (duration == 0 ? 1 : duration);
bottomProgressBar.setProgress(progress);
}
if (!mChangePosition && !mChangeVolume) {
onEvent(JCUserActionStandard.ON_CLICK_BLANK);
onClickUiToggle();
}
break;
}
} else if (id == R.id.bottom_seek_progress) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
cancelDismissControlViewTimer();
break;
case MotionEvent.ACTION_UP:
startDismissControlViewTimer();
break;
}
}
return super.onTouch(v, event);
}
@Override
public void onClick(View v) {
super.onClick(v);
int i = v.getId();
if (i == R.id.thumb) {
if (TextUtils.isEmpty(url)) {
Toast.makeText(getContext(), getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show();
return;
}
if (currentState == CURRENT_STATE_NORMAL) {
if (!url.startsWith("file") && !url.startsWith("/") &&
!JCUtils.isWifiConnected(getContext()) && !WIFI_TIP_DIALOG_SHOWED) {
showWifiDialog();
return;
}
startVideo();
} else if (currentState == CURRENT_STATE_AUTO_COMPLETE) {
onClickUiToggle();
}
} else if (i == R.id.surface_container) {
startDismissControlViewTimer();
} else if (i == R.id.back) {
backPress();
} else if (i == R.id.back_tiny) {
backPress();
}
}
@Override
public void showWifiDialog() {
super.showWifiDialog();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMessage(getResources().getString(R.string.tips_not_wifi));
builder.setPositiveButton(getResources().getString(R.string.tips_not_wifi_confirm), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
startVideo();
WIFI_TIP_DIALOG_SHOWED = true;
}
});
builder.setNegativeButton(getResources().getString(R.string.tips_not_wifi_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
dialog.dismiss();
clearFullscreenLayout();
}
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
dialog.dismiss();
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
dialog.dismiss();
clearFullscreenLayout();
}
}
});
builder.create().show();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
super.onStartTrackingTouch(seekBar);
cancelDismissControlViewTimer();
}
public void startPlayVideo(){
startButton.performClick();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
super.onStopTrackingTouch(seekBar);
startDismissControlViewTimer();
}
public void startVideo() {
prepareMediaPlayer();
onEvent(JCUserActionStandard.ON_CLICK_START_THUMB);
}
public void onClickUiToggle() {
if (currentState == CURRENT_STATE_PREPARING) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPreparingClear();
} else {
changeUiToPreparingShow();
}
} else if (currentState == CURRENT_STATE_PLAYING) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPlayingClear();
} else {
changeUiToPlayingShow();
}
} else if (currentState == CURRENT_STATE_PAUSE) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPauseClear();
} else {
changeUiToPauseShow();
}
} else if (currentState == CURRENT_STATE_AUTO_COMPLETE) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToCompleteClear();
} else {
changeUiToCompleteShow();
}
} else if (currentState == CURRENT_STATE_PLAYING_BUFFERING_START) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPlayingBufferingClear();
} else {
changeUiToPlayingBufferingShow();
}
}
}
public void onCLickUiToggleToClear() {
if (currentState == CURRENT_STATE_PREPARING) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPreparingClear();
} else {
}
} else if (currentState == CURRENT_STATE_PLAYING) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPlayingClear();
} else {
}
} else if (currentState == CURRENT_STATE_PAUSE) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPauseClear();
} else {
}
} else if (currentState == CURRENT_STATE_AUTO_COMPLETE) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToCompleteClear();
} else {
}
} else if (currentState == CURRENT_STATE_PLAYING_BUFFERING_START) {
if (bottomContainer.getVisibility() == View.VISIBLE) {
changeUiToPlayingBufferingClear();
} else {
}
}
}
@Override
public void setProgressAndText() {
super.setProgressAndText();
int position = getCurrentPositionWhenPlaying();
int duration = getDuration();
int progress = position * 100 / (duration == 0 ? 1 : duration);
if (progress != 0) bottomProgressBar.setProgress(progress);
}
@Override
public void setBufferProgress(int bufferProgress) {
super.setBufferProgress(bufferProgress);
if (bufferProgress != 0) bottomProgressBar.setSecondaryProgress(bufferProgress);
}
@Override
public void resetProgressAndTime() {
super.resetProgressAndTime();
bottomProgressBar.setProgress(0);
bottomProgressBar.setSecondaryProgress(0);
}
//Unified management Ui
public void changeUiToNormal() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.VISIBLE, View.INVISIBLE, View.VISIBLE,
View.INVISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.VISIBLE, View.INVISIBLE, View.VISIBLE,
View.INVISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToPreparingShow() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.VISIBLE, View.INVISIBLE, View.INVISIBLE,
View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.VISIBLE, View.INVISIBLE, View.INVISIBLE,
View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToPreparingClear() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.VISIBLE, View.INVISIBLE, View.INVISIBLE,
View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.VISIBLE, View.INVISIBLE, View.INVISIBLE,
View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_TINY:
break;
}
}
//JustPreparedUi
@Override
public void onPrepared() {
super.onPrepared();
setAllControlsVisible(View.VISIBLE, View.INVISIBLE, View.INVISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE);
startDismissControlViewTimer();
}
public void changeUiToPlayingShow() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.VISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.VISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToPlayingClear() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE);
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE);
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToPauseShow() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.VISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.VISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToPauseClear() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToPlayingBufferingShow() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.INVISIBLE,
View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.INVISIBLE,
View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToPlayingBufferingClear() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToCompleteShow() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.VISIBLE,
View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.VISIBLE, View.VISIBLE, View.VISIBLE,
View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToCompleteClear() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.VISIBLE,
View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.VISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.VISIBLE,
View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.VISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void changeUiToError() {
switch (currentScreen) {
case SCREEN_LAYOUT_NORMAL:
case SCREEN_LAYOUT_LIST:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.VISIBLE,
View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_FULLSCREEN:
setAllControlsVisible(View.INVISIBLE, View.INVISIBLE, View.VISIBLE,
View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE);
updateStartImage();
break;
case SCREEN_WINDOW_TINY:
break;
}
}
public void setAllControlsVisible(int topCon, int bottomCon, int startBtn, int loadingPro,
int thumbImg, int coverImg, int bottomPro) {
topContainer.setVisibility(topCon);
bottomContainer.setVisibility(bottomCon);
startButton.setVisibility(startBtn);
loadingProgressBar.setVisibility(loadingPro);
thumbImageView.setVisibility(thumbImg);
bottomProgressBar.setVisibility(bottomPro);
}
public void updateStartImage() {
if (currentState == CURRENT_STATE_PLAYING) {
startButton.setImageResource(R.drawable.jc_click_pause_selector);
} else if (currentState == CURRENT_STATE_ERROR) {
startButton.setImageResource(R.drawable.jc_click_error_selector);
} else {
startButton.setImageResource(R.drawable.jc_click_play_selector);
}
}
protected Dialog mProgressDialog;
protected ProgressBar mDialogProgressBar;
protected TextView mDialogSeekTime;
protected TextView mDialogTotalTime;
protected ImageView mDialogIcon;
@Override
public void showProgressDialog(float deltaX, String seekTime, int seekTimePosition, String totalTime, int totalTimeDuration) {
super.showProgressDialog(deltaX, seekTime, seekTimePosition, totalTime, totalTimeDuration);
if (mProgressDialog == null) {
View localView = LayoutInflater.from(getContext()).inflate(R.layout.jc_dialog_progress, null);
mDialogProgressBar = ((ProgressBar) localView.findViewById(R.id.duration_progressbar));
mDialogSeekTime = ((TextView) localView.findViewById(R.id.tv_current));
mDialogTotalTime = ((TextView) localView.findViewById(R.id.tv_duration));
mDialogIcon = ((ImageView) localView.findViewById(R.id.duration_image_tip));
mProgressDialog = new Dialog(getContext(), R.style.jc_style_dialog_progress);
mProgressDialog.setContentView(localView);
mProgressDialog.getWindow().addFlags(Window.FEATURE_ACTION_BAR);
mProgressDialog.getWindow().addFlags(32);
mProgressDialog.getWindow().addFlags(16);
mProgressDialog.getWindow().setLayout(-2, -2);
WindowManager.LayoutParams localLayoutParams = mProgressDialog.getWindow().getAttributes();
localLayoutParams.gravity = Gravity.CENTER;
mProgressDialog.getWindow().setAttributes(localLayoutParams);
}
if (!mProgressDialog.isShowing()) {
mProgressDialog.show();
}
mDialogSeekTime.setText(seekTime);
mDialogTotalTime.setText(" / " + totalTime);
mDialogProgressBar.setProgress(totalTimeDuration <= 0 ? 0 : (seekTimePosition * 100 / totalTimeDuration));
if (deltaX > 0) {
mDialogIcon.setBackgroundResource(R.drawable.jc_forward_icon);
} else {
mDialogIcon.setBackgroundResource(R.drawable.jc_backward_icon);
}
onCLickUiToggleToClear();
}
@Override
public void dismissProgressDialog() {
super.dismissProgressDialog();
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
}
protected Dialog mVolumeDialog;
protected ProgressBar mDialogVolumeProgressBar;
protected TextView mDialogVolumeTextView;
protected ImageView mDialogVolumeImageView;
@Override
public void showVolumeDialog(float deltaY, int volumePercent) {
super.showVolumeDialog(deltaY, volumePercent);
if (mVolumeDialog == null) {
View localView = LayoutInflater.from(getContext()).inflate(R.layout.jc_dialog_volume, null);
mDialogVolumeImageView = ((ImageView) localView.findViewById(R.id.volume_image_tip));
mDialogVolumeTextView = ((TextView) localView.findViewById(R.id.tv_volume));
mDialogVolumeProgressBar = ((ProgressBar) localView.findViewById(R.id.volume_progressbar));
mVolumeDialog = new Dialog(getContext(), R.style.jc_style_dialog_progress);
mVolumeDialog.setContentView(localView);
mVolumeDialog.getWindow().addFlags(8);
mVolumeDialog.getWindow().addFlags(32);
mVolumeDialog.getWindow().addFlags(16);
mVolumeDialog.getWindow().setLayout(-2, -2);
WindowManager.LayoutParams localLayoutParams = mVolumeDialog.getWindow().getAttributes();
localLayoutParams.gravity = Gravity.CENTER;
mVolumeDialog.getWindow().setAttributes(localLayoutParams);
}
if (!mVolumeDialog.isShowing()) {
mVolumeDialog.show();
}
if (volumePercent <= 0) {
mDialogVolumeImageView.setBackgroundResource(R.drawable.jc_close_volume);
} else {
mDialogVolumeImageView.setBackgroundResource(R.drawable.jc_add_volume);
}
if (volumePercent > 100) {
volumePercent = 100;
} else if (volumePercent < 0) {
volumePercent = 0;
}
mDialogVolumeTextView.setText(volumePercent + "%");
mDialogVolumeProgressBar.setProgress(volumePercent);
onCLickUiToggleToClear();
}
@Override
public void dismissVolumeDialog() {
super.dismissVolumeDialog();
if (mVolumeDialog != null) {
mVolumeDialog.dismiss();
}
}
protected Dialog mBrightnessDialog;
protected ProgressBar mDialogBrightnessProgressBar;
protected TextView mDialogBrightnessTextView;
@Override
public void showBrightnessDialog(int brightnessPercent) {
super.showBrightnessDialog(brightnessPercent);
if (mBrightnessDialog == null) {
View localView = LayoutInflater.from(getContext()).inflate(R.layout.jc_dialog_brightness, null);
mDialogBrightnessTextView = ((TextView) localView.findViewById(R.id.tv_brightness));
mDialogBrightnessProgressBar = ((ProgressBar) localView.findViewById(R.id.brightness_progressbar));
mBrightnessDialog = new Dialog(getContext(), R.style.jc_style_dialog_progress);
mBrightnessDialog.setContentView(localView);
mBrightnessDialog.getWindow().addFlags(Window.FEATURE_ACTION_BAR);
mBrightnessDialog.getWindow().addFlags(32);
mBrightnessDialog.getWindow().addFlags(16);
mBrightnessDialog.getWindow().setLayout(-2, -2);
WindowManager.LayoutParams localLayoutParams = mBrightnessDialog.getWindow().getAttributes();
localLayoutParams.gravity = Gravity.CENTER;
mBrightnessDialog.getWindow().setAttributes(localLayoutParams);
}
if (!mBrightnessDialog.isShowing()) {
mBrightnessDialog.show();
}
if (brightnessPercent > 100) {
brightnessPercent = 100;
} else if (brightnessPercent < 0) {
brightnessPercent = 0;
}
mDialogBrightnessTextView.setText(brightnessPercent + "%");
mDialogBrightnessProgressBar.setProgress(brightnessPercent);
onCLickUiToggleToClear();
}
@Override
public void dismissBrightnessDialog() {
super.dismissBrightnessDialog();
if (mBrightnessDialog != null) {
mBrightnessDialog.dismiss();
}
}
public void startDismissControlViewTimer() {
cancelDismissControlViewTimer();
DISMISS_CONTROL_VIEW_TIMER = new Timer();
mDismissControlViewTimerTask = new DismissControlViewTimerTask();
DISMISS_CONTROL_VIEW_TIMER.schedule(mDismissControlViewTimerTask, 2500);
}
public void cancelDismissControlViewTimer() {
if (DISMISS_CONTROL_VIEW_TIMER != null) {
DISMISS_CONTROL_VIEW_TIMER.cancel();
}
if (mDismissControlViewTimerTask != null) {
mDismissControlViewTimerTask.cancel();
}
}
public class DismissControlViewTimerTask extends TimerTask {
@Override
public void run() {
if (currentState != CURRENT_STATE_NORMAL
&& currentState != CURRENT_STATE_ERROR
&& currentState != CURRENT_STATE_AUTO_COMPLETE) {
if (getContext() != null && getContext() instanceof Activity) {
((Activity) getContext()).runOnUiThread(new Runnable() {
@Override
public void run() {
bottomContainer.setVisibility(View.INVISIBLE);
topContainer.setVisibility(View.INVISIBLE);
startButton.setVisibility(View.INVISIBLE);
if (currentScreen != SCREEN_WINDOW_TINY) {
bottomProgressBar.setVisibility(View.VISIBLE);
}
}
});
}
}
}
}
@Override
public void onAutoCompletion() {
super.onAutoCompletion();
cancelDismissControlViewTimer();
}
@Override
public void onCompletion() {
super.onCompletion();
cancelDismissControlViewTimer();
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<rotate
android:duration="5"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-2" />
</set>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<rotate
android:duration="20"
android:fromDegrees="-2"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="0" />
</set>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#a5ffffff" />
<size android:height="4.0dip" />
<corners android:radius="1.0dip" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<solid android:color="#ffe0e0e0" />
<size android:height="4.0dip" />
<corners android:radius="1.0dip" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="#fff85959" />
<size android:height="4.0dip" />
<corners android:radius="1.0dip" />
</shape>
</clip>
</item>
</layer-list>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#a5ffffff" />
<size android:height="1.0dip" />
<corners android:radius="1.5dip" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<solid android:color="#ffffffff" />
<size android:height="1.0dip" />
<corners android:radius="1.5dip" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="#fff85959" />
<size android:height="1.0dip" />
<corners android:radius="1.5dip" />
</shape>
</clip>
</item>
</layer-list>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/jc_seek_thumb_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/jc_seek_thumb_normal" />
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/jc_back_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/jc_back_normal" />
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/jc_back_tiny_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/jc_back_tiny_normal" />
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/jc_error_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/jc_error_normal" />
</selector>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/jc_pause_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/jc_pause_normal" />
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/jc_play_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/jc_play_normal" />
</selector>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#ffffffff" />
<corners android:radius="2dp" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="#fff85959" />
<corners android:radius="2dp" />
</shape>
</clip>
</item>
</layer-list>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#cc000000" />
<corners
android:bottomLeftRadius="6.0dip"
android:bottomRightRadius="6.0dip"
android:topLeftRadius="6.0dip"
android:topRightRadius="6.0dip" />
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/jc_loading_bg"
android:fromDegrees="0.0"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:toDegrees="360.0" />

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffffff" />
<size
android:height="15.0dip"
android:width="15.0dip" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#fff0f0f0" />
<size
android:height="15.0dip"
android:width="15.0dip" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#ffffffff" />
<corners android:radius="2.0dip" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape>
<solid android:color="#fff85959" />
<corners android:radius="2.0dip" />
</shape>
</clip>
</item>
</layer-list>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/jc_dialog_progress_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="155dp"
android:layout_height="120dp"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:src="@drawable/jc_brightness_video" />
<TextView
android:id="@+id/tv_brightness"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:textColor="#ffffffff"
android:textSize="16sp" />
<ProgressBar
android:id="@+id/brightness_progressbar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="fill_parent"
android:layout_height="3dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="20dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:layout_marginTop="8dp"
android:max="100"
android:progressDrawable="@drawable/jc_dialog_progress" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/jc_dialog_progress_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="152dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/duration_image_tip"
android:layout_width="36dp"
android:layout_height="27dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff85959"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffffff"
android:textSize="14sp" />
</LinearLayout>
<ProgressBar
android:id="@+id/duration_progressbar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="fill_parent"
android:layout_height="4dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:max="100"
android:progressDrawable="@drawable/jc_dialog_progress" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/jc_dialog_progress_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="155dp"
android:layout_height="120dp"
android:orientation="vertical">
<ImageView
android:id="@+id/volume_image_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp" />
<TextView
android:id="@+id/tv_volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:textColor="#ffffffff"
android:textSize="16sp" />
<ProgressBar
android:id="@+id/volume_progressbar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="fill_parent"
android:layout_height="3dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="20dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:layout_marginTop="8dp"
android:max="100"
android:progressDrawable="@drawable/jc_dialog_progress" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<FrameLayout
android:id="@+id/surface_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<LinearLayout
android:id="@+id/layout_bottom"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:background="#99000000"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:text="00:00"
android:textColor="#ffffff" />
<SeekBar
android:id="@+id/bottom_seek_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:background="@null"
android:max="100"
android:maxHeight="4dp"
android:minHeight="4dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:progressDrawable="@drawable/jc_bottom_seek_progress"
android:thumb="@drawable/jc_bottom_seek_thumb" />
<TextView
android:id="@+id/total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#ffffff" />
<ImageView
android:id="@+id/fullscreen"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingRight="16dp"
android:scaleType="center"
android:src="@drawable/jc_enlarge" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_top"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@drawable/jc_title_bg"
android:gravity="center_vertical"
android:orientation="horizontal">
</LinearLayout>
<ProgressBar
android:id="@+id/loading"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:indeterminateDrawable="@drawable/jc_loading"
android:visibility="invisible" />
<ImageView
android:id="@+id/start"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:src="@drawable/jc_click_play_selector" />
</RelativeLayout>

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:descendantFocusability="blocksDescendants">
<FrameLayout
android:id="@+id/surface_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<ImageView
android:id="@+id/thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="#000000"
android:scaleType="fitCenter" />
<LinearLayout
android:id="@+id/layout_bottom"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="invisible">
<TextView
android:id="@+id/current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:text="00:00"
android:textColor="#ffffff" />
<SeekBar
android:id="@+id/bottom_seek_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:background="@null"
android:max="100"
android:maxHeight="1.0dip"
android:minHeight="1.0dip"
android:paddingBottom="8dp"
android:paddingLeft="12dp"
android:paddingRight="22dp"
android:paddingTop="8dp"
android:progressDrawable="@drawable/jc_bottom_seek_progress"
android:thumb="@drawable/jc_bottom_seek_thumb" />
<TextView
android:id="@+id/total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#ffffff" />
<ImageView
android:id="@+id/fullscreen"
android:layout_width="24.5dp"
android:layout_height="fill_parent"
android:layout_marginLeft="14.0dip"
android:layout_marginRight="14.0dip"
android:scaleType="centerInside"
android:src="@drawable/jc_enlarge" />
</LinearLayout>
<ProgressBar
android:id="@+id/bottom_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="1.5dp"
android:layout_alignParentBottom="true"
android:max="100"
android:progressDrawable="@drawable/jc_bottom_progress" />
<ImageView
android:id="@+id/back_tiny"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="6dp"
android:layout_marginTop="6dp"
android:background="@drawable/jc_click_back_tiny_selector"
android:visibility="visible" />
<LinearLayout
android:id="@+id/layout_top"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/back"
android:layout_width="23dp"
android:layout_height="match_parent"
android:paddingLeft="14dp"
android:scaleType="centerInside"
android:src="@drawable/jc_click_back_selector" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:textColor="@android:color/white"
android:textSize="18sp" />
</LinearLayout>
<ProgressBar
android:id="@+id/loading"
android:layout_width="@dimen/jc_start_button_w_h_normal"
android:layout_height="@dimen/jc_start_button_w_h_normal"
android:layout_centerHorizontal="true"
android:layout_below="@+id/layout_top"
android:layout_marginTop="@dimen/top"
android:indeterminateDrawable="@drawable/jc_loading"
android:visibility="invisible" />
<ImageView
android:id="@+id/start"
android:layout_width="@dimen/jc_start_button_w_h_normal"
android:layout_height="@dimen/jc_start_button_w_h_normal"
android:layout_centerHorizontal="true"
android:layout_below="@+id/layout_top"
android:layout_marginTop="@dimen/top"
android:layout_gravity="center_vertical"
android:src="@drawable/jc_click_play_selector" />
</RelativeLayout>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="tips_not_wifi">Você está usando a rede móvel, você deseja mesmo ver o video?</string>
<string name="tips_not_wifi_confirm">Continuar</string>
<string name="tips_not_wifi_cancel">Parar</string>
<string name="no_url">Sem Vídeo</string>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="tips_not_wifi">Şu anda mobil veriyi kullanıyorsunuz, yüksek veri kaybına yol açabilir</string>
<string name="tips_not_wifi_confirm">Devam Et</string>
<string name="tips_not_wifi_cancel">Durdur</string>
<string name="no_url">URL Bulunamadı</string>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="tips_not_wifi">您当前正在使用移动网络,继续播放将消耗流量</string>
<string name="tips_not_wifi_confirm">继续播放</string>
<string name="tips_not_wifi_cancel">停止播放</string>
<string name="no_url">播放地址无效</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View File

@ -0,0 +1,5 @@
<resources>
<dimen name="jc_start_button_w_h_normal">45dp</dimen>
<dimen name="jc_start_button_w_h_fullscreen">62dp</dimen>
<dimen name="top">30dp</dimen>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="tips_not_wifi">You are currently using the mobile network, the player will continue to consume traffic</string>
<string name="tips_not_wifi_confirm">Resume</string>
<string name="tips_not_wifi_cancel">Stop play</string>
<string name="no_url">No mUrl</string>
</resources>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="jc_style_dialog_progress" parent="@android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowAnimationStyle">@style/jc_popup_toast_anim</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
<style name="jc_popup_toast_anim" parent="@android:style/Animation">
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
</style>
<style name="jc_vertical_progressBar">
<item name="android:maxWidth">12dp</item>
<item name="android:indeterminateOnly">false</item>
<item name="android:indeterminateDrawable">
@android:drawable/progress_indeterminate_horizontal
</item>
<item name="android:progressDrawable">@drawable/jc_volume_progress_bg</item>
<item name="android:indeterminateDuration">3500</item>
<item name="android:indeterminateBehavior">repeat</item>
<item name="android:minWidth">1dp</item>
</style>
</resources>

View File

@ -0,0 +1,15 @@
package fm.jiecao.jcvideoplayer_lib;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

24
build.gradle Normal file
View File

@ -0,0 +1,24 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
// classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.2'
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
allprojects {
repositories {
jcenter()
maven {
url "http://repo.baichuan-android.taobao.com/content/groups/BaichuanRepositories/"
}
}
}
ext {
compileSdkVersion = 25
buildToolsVersion = "25.0.3"
minSdkVersion = 16
targetSdkVersion = 21
}

115
iFish7/build.gradle Normal file
View File

@ -0,0 +1,115 @@
apply plugin: 'com.android.application'
android {
signingConfigs {
debug {
keyAlias 'android.keystore'
keyPassword 'ifish7'
storeFile file('D:/Android/iFish7/ifish7.keystore')
storePassword 'ifish7'
}
}
useLibrary 'org.apache.http.legacy'
lintOptions {
checkReleaseBuilds false
abortOnError false
}
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
applicationId "com.ifish.activity"
versionCode 20
versionName "4.6.1"
multiDexEnabled true
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.debug
}
release {
minifyEnabled false
}
}
dexOptions {
incremental true
javaMaxHeapSize '4g'
}
}
repositories{
flatDir{
dirs 'libs' //aar的目录地址
}
}
dependencies {
compile project(':p2PCore')
//
compile project(':umeng_sharesdk_library')
//
compile 'com.google.code.gson:gson:2.4'
compile files('libs/bugly_1.2.6_release.jar')
//bugly
compile files('libs/commons-io-1.4.jar')
compile files('libs/EMTMF_0101_1608016.jar')
compile files('libs/locSDK_6.13.jar')
compile files('libs/mina-core-2.0.7.jar')
compile files('libs/TalkingDataAnalytics_V2.1.37.jar')
compile files('libs/umeng_social_sdk.jar')
compile 'de.greenrobot:eventbus:2.4.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
compile 'com.jiechic.library:xUtils:2.6.14'
compile 'com.google.zxing:core:3.3.0'
compile project(':uikit')
//
compile 'com.android.support:multidex:1.0.1'
//65535
compile files('libs/cosinesdk.jar')
compile files('libs/AMap_Services_V2.3.1.jar')
//
compile files('libs/Android_2DMap_V2.4.0.jar')
//
compile files('libs/MobCommons-2016.1012.1447.jar')
compile files('libs/MobTools-2016.1012.1447.jar')
compile name: 'SMSSDK-2.1.2', ext: 'aar'
//MOB短信平台
compile 'com.jude:rollviewpager:1.4.5'
//ViewPager
compile project(':BageView')
//
compile project(':umeng_community_library')
//
compile 'jp.wasabeef:picasso-transformations:2.1.0'
//Picasso
compile 'com.android.support:design:23+'
compile 'com.github.bumptech.glide:glide:3.7.0'
//Glide
compile 'cn.bingoogolapple:bga-refreshlayout:1.1.7@aar'
//
/**阿里百川*/
//
compile name: 'securityguardaar3-5.1.81', ext: 'aar'
// compile 'com.taobao.android:securityguardaar3:5.1.81@aar'
//UT
compile 'com.taobao.android:utdid4all:1.1.5.3_proguard@jar'
compile 'com.alibaba.mtl:app-monitor-sdk:2.5.1.3_for_bc_proguard@jar'
//
compile 'com.ali.auth.sdk:alibabauth_core:1.1.4@jar'
compile 'com.ali.auth.sdk:alibabauth_ui:1.1.4@aar'
compile 'com.ali.auth.sdk:alibabauth_ext:1.1.4@jar'
//SDK
compile 'com.alibaba.sdk.android:alibc_trade_sdk:3.1.1.11@aar'
//Mtop网关
compile 'com.taobao.android:mtopsdk_allinone_open:1.2.2.4@jar'
//applink
compile 'com.taobao.android:alibc_applink:2.0.0.9@jar'
//
compile 'com.alibaba.alipay:alipaySingle:20160825@jar'
/**阿里百川*/
compile project(':JCVideo_Library')
}
//apply plugin: 'com.getkeepsafe.dexcount'

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
iFish7/libs/cosinesdk.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
iFish7/libs/locSDK_6.13.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More