初始化
|
|
@ -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'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
PUBLISH_AAR_ARTIFACT_ID=bga-badgeview
|
||||
PUBLISH_AAR_DESCRIPTION=Android BadgeView Library
|
||||
PUBLISH_AAR_GITHUB_REPOSITORIES_NAME=BGABadgeView-Android
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<manifest package="cn.bingoogolapple.badgeview"/>
|
||||
<!--
|
||||
ss-->
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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'
|
||||
}
|
||||
|
||||
|
|
@ -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 *;
|
||||
#}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 260 B |
|
After Width: | Height: | Size: 317 B |
|
After Width: | Height: | Size: 531 B |
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 717 B |
|
After Width: | Height: | Size: 167 B |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 958 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 226 B |
|
After Width: | Height: | Size: 922 B |
|
After Width: | Height: | Size: 946 B |
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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" />
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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'
|
||||