Przeglądaj źródła

添加通用版有米积分任务

zengjiebin 7 lat temu
rodzic
commit
bcf0eaa0a8

+ 2 - 0
app/build.gradle

@@ -282,6 +282,8 @@ dependencies {
     implementation "com.liulishuo.okdownload:sqlite:1.0.4"
     // provide okhttp to connect to backend
     implementation "com.liulishuo.okdownload:okhttp:1.0.4"
+
+    implementation(name: 'YoumiSdk_v8.3.0_2018-09-20', ext: 'aar')
 }
 
 static def releaseTime() {

BIN
app/libs/YoumiSdk_v8.3.0_2018-09-20.aar


+ 9 - 0
app/src/main/AndroidManifest.xml

@@ -726,6 +726,15 @@
             </intent-filter>
         </receiver>
         <!--end幂动科技-->
+        <!--start 有米科技-->
+
+        <activity
+            android:name="com.youmi.android.offerdemo.PermissionCheckActivity"
+            android:screenOrientation="portrait" />
+        <activity
+            android:name="com.youmi.android.offerdemo.YoumiOffersAdsDemo"
+            android:screenOrientation="portrait" />
+        <!--end 有米科技-->
     </application>
 
 

+ 4 - 0
app/src/main/java/com/sheep/gamegroup/util/CommonUtil.java

@@ -456,6 +456,7 @@ public class CommonUtil {
     public static final int JUMP_XIAO_MI = 15;//小米游戏列表
     //TODO 这里移动积分兑换的id需要替换
     public static final int JUMP_EXCHANGE_CMCC = 1000025;//移动积分兑换
+    public static final int JUMP_YM = 1000026;//有米积分
     public static final int JUMP_GMAE = 16;//游戏
     public static final int JUMP_FIND_RECOMMEND = 17;//推荐
     public static final int JUMP_WATCH_FOCUS = 18;//看点
@@ -526,6 +527,9 @@ public class CommonUtil {
             case JUMP_EXCHANGE_CMCC://移动积分兑换
                 Jump2View.getInstance().goActExchangeCMCC(context);
                 break;
+            case JUMP_YM://有米积分
+                Jump2View.getInstance().goYm((Activity) context);
+                break;
             default:
                 String url = entity.getUrl();
                 if (TextUtils.isEmpty(url))

+ 19 - 2
app/src/main/java/com/sheep/gamegroup/util/Jump2View.java

@@ -12,7 +12,6 @@ import android.text.TextUtils;
 import android.view.Gravity;
 import android.view.View;
 
-import com.liulishuo.okdownload.DownloadTask;
 import com.sheep.gamegroup.absBase.BaseActivity;
 import com.sheep.gamegroup.greendao.download.DownLoadInfo;
 import com.sheep.gamegroup.model.entity.Advertising;
@@ -45,6 +44,7 @@ import com.sheep.gamegroup.view.activity.ActCreditCardTaskList;
 import com.sheep.gamegroup.view.activity.ActCreditCardWeb;
 import com.sheep.gamegroup.view.activity.ActDownloadWelfareList;
 import com.sheep.gamegroup.view.activity.ActEverydayPlayGame;
+import com.sheep.gamegroup.view.activity.ActExchangeCMCC;
 import com.sheep.gamegroup.view.activity.ActFindGame;
 import com.sheep.gamegroup.view.activity.ActFindInformation;
 import com.sheep.gamegroup.view.activity.ActGameAccount;
@@ -79,7 +79,6 @@ import com.sheep.gamegroup.view.activity.ActUserLabelList;
 import com.sheep.gamegroup.view.activity.ActWeb;
 import com.sheep.gamegroup.view.activity.ActXiaomiGame;
 import com.sheep.gamegroup.view.activity.ActXinwanWeb;
-import com.sheep.gamegroup.view.activity.ActExchangeCMCC;
 import com.sheep.gamegroup.view.activity.AskGetMoneyAct;
 import com.sheep.gamegroup.view.activity.BindOrChangeWeixinAct;
 import com.sheep.gamegroup.view.activity.ChangeTelAct;
@@ -122,6 +121,8 @@ import com.sheep.jiuyan.samllsheep.service.ListenerShotNewService;
 import com.sheep.jiuyan.samllsheep.service.ListenerShotService;
 import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.SpUtils;
+import com.youmi.android.offer.BaseActYmPermissionCheck;
+import com.youmi.android.offerdemo.PermissionCheckActivity;
 
 import org.xutils.ex.DbException;
 
@@ -2020,4 +2021,20 @@ public class Jump2View {
     public void startDownloadService(Context context, DownLoadInfo downLoadInfo) {
         context.startService(new Intent(context, DownloadService.class).putExtra("download_url", downLoadInfo.getMDownloadUrl()).putExtra("file_path", downLoadInfo.getMApkPath()));
     }
+
+    /**
+     * 有米科技
+     * @param activity
+     */
+    public void goTestYm(Activity activity) {
+        activity.startActivity(new Intent(activity, PermissionCheckActivity.class));
+    }
+    /**
+     * 有米科技
+     * @param activity
+     */
+    public void goYm(Activity activity) {
+        if(activity instanceof BaseActYmPermissionCheck)
+            ((BaseActYmPermissionCheck) activity).checkOrShowYmOffersAds();
+    }
 }

+ 7 - 1
app/src/main/java/com/sheep/gamegroup/util/TestUtil.java

@@ -223,7 +223,7 @@ public class TestUtil {
      */
     public static void test(final Activity activity) {
         final String[] items = {"复制token","复制打点数据","从jenkins下载小绵羊安装包","龙猫竞猜","龙猫竞猜-scheme",
-                "手机型号测试","测试通知栏", "测试自定义通知栏","测试自定义通知栏2",
+                "有米科技测试","有米科技","手机型号测试","测试通知栏", "测试自定义通知栏","测试自定义通知栏2",
                 "开启通知栏权限0","开启通知栏权限1","开启通知栏权限2","开启通知栏权限3",
                 "开启通知栏权限","通知栏权限1","通知栏权限2","通知栏权限8.0","测试支付","测试内部h5", "测试外部h5",
                 "会长推广游戏","移动积分兑换","审核中心","检查正版","crc32","loading","progress","查看截图",
@@ -269,6 +269,12 @@ public class TestUtil {
                                 bdIntent2.putExtras(bundle2);
                                 activity.sendBroadcast(bdIntent2);
                                 break;
+                            case "有米科技测试":
+                                Jump2View.getInstance().goTestYm(activity);
+                                break;
+                            case "有米科技":
+                                Jump2View.getInstance().goYm(activity);
+                                break;
                             case "手机型号测试":
                                 G.showToast(android.os.Build.BRAND);
                                 break;

+ 2 - 1
app/src/main/java/com/sheep/gamegroup/view/activity/ActMain.java

@@ -43,6 +43,7 @@ import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.PackageUtil;
 import com.sheep.jiuyan.samllsheep.utils.SpUtils;
+import com.youmi.android.offer.BaseActYmPermissionCheck;
 
 import org.greenrobot.eventbus.EventBus;
 import org.greenrobot.eventbus.Subscribe;
@@ -67,7 +68,7 @@ import static com.sheep.gamegroup.view.adapter.TryMakeMoneyAdp.PUBLIC_TAG_PREFIX
  * Created by realicing on 2018/9/6.
  * realicing@sina.com
  */
-public class ActMain extends BaseActivity {
+public class ActMain extends BaseActYmPermissionCheck  {
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         StatusBarUtils.setTranslucent(this);

+ 6 - 0
app/src/main/java/com/sheep/gamegroup/view/fragment/FgtSmallSheep.java

@@ -596,6 +596,9 @@ public class FgtSmallSheep extends BaseFragment implements SmallSheepContract.Vi
         initTitleCardLayout(activity.getApplicationContext());
         TestUtil.testChange(activity, test_change);
         TestUtil.testChangeUser(activity, test_change_user);
+        ymHomeListEty = new HomeListEntity();
+        ymHomeListEty.setTitle("有米积分");
+        ymHomeListEty.setJump(String.valueOf(CommonUtil.JUMP_YM));
         if (pagePresenter != null) {
             initData();
         }
@@ -603,6 +606,7 @@ public class FgtSmallSheep extends BaseFragment implements SmallSheepContract.Vi
         CommonUtil.getInstance().initUrlConfigByNet(null, null);
         isShowRedPackage();
     }
+    private HomeListEntity ymHomeListEty;
 
 
     public void initView() {
@@ -856,6 +860,7 @@ public class FgtSmallSheep extends BaseFragment implements SmallSheepContract.Vi
         } else {
             home_list_gridview_layout.setVisibility(View.VISIBLE);
             fullHomeList.clear();
+            fullHomeList.add(ymHomeListEty);
             CommonUtil.getInstance().splitHomeList(cacheHomeListEtyList, homeListEntitys, fullHomeList);
             full_home_list_rv.setVisibility(fullHomeList.isEmpty() ? View.GONE : View.VISIBLE);
             boolean isShowQB = false;
@@ -1233,6 +1238,7 @@ public class FgtSmallSheep extends BaseFragment implements SmallSheepContract.Vi
                 homeListEntitysGridview.clear();
                 homeListEntitysListview.clear();
                 fullHomeList.clear();
+                fullHomeList.add(ymHomeListEty);
                 CommonUtil.getInstance().splitHomeList(homeListEntityList, homeListEntitys, fullHomeList);
                 full_home_list_rv.setVisibility(fullHomeList.isEmpty() ? View.GONE : View.VISIBLE);
                 boolean isShowQB = false;

+ 62 - 0
app/src/main/java/com/youmi/android/offer/BaseActYmPermissionCheck.java

@@ -0,0 +1,62 @@
+package com.youmi.android.offer;
+
+import android.os.Build;
+import android.support.annotation.NonNull;
+
+import com.sheep.gamegroup.absBase.BaseActivity;
+
+/**
+ * Android 6.0 上权限分为<b>正常</b>和<b>危险</b>级别
+ * <ul>
+ * <li>正常级别权限:开发者仅仅需要在AndroidManifext.xml上声明,那么应用就会被允许拥有该权限,如:android.permission.INTERNET</li>
+ * <li>危险级别权限:开发者需要在AndroidManifext.xml上声明,并且在运行时进行申请,而且用户允许了,应用才会被允许拥有该权限,如:android.permission.WRITE_EXTERNAL_STORAGE</li>
+ * </ul>
+ * 有米的以下权限需要在Android6.0上被允许,有米广告sdk才能正常工作,开发者需要在调用有米的任何代码之前,提前让用户允许权限
+ * <ul>
+ * <li>必须申请的权限
+ * <ul>
+ * <li>android.permission.READ_PHONE_STATE</li>
+ * <li>android.permission.WRITE_EXTERNAL_STORAGE</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * @since 2015-12-10 16:36
+ */
+public abstract class BaseActYmPermissionCheck extends BaseActivity {
+
+    //检查权限并启动有米积分墙界面
+    public void checkOrShowYmOffersAds() {
+        ymPermissionUtil = new YmPermissionUtil(this);
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            ymPermissionUtil.showYmOffersAds();
+            return;
+        }
+
+        ymPermissionUtil.checkPermissions();
+
+    }
+
+    private YmPermissionUtil ymPermissionUtil;
+
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        if (ymPermissionUtil != null)
+            ymPermissionUtil.onRequestPermissionsResult(requestCode, permissions, grantResults);
+    }
+
+
+    /**
+     * 退出时回收资源
+     */
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (ymPermissionUtil != null)
+            ymPermissionUtil.onDestroy();
+
+    }
+
+}

+ 19 - 0
app/src/main/java/com/youmi/android/offer/YmConfig.java

@@ -0,0 +1,19 @@
+package com.youmi.android.offer;
+
+import com.sheep.gamegroup.util.TestUtil;
+
+/**
+ * Created by realicing on 2018/10/29.
+ * realicing@sina.com
+ */
+public class YmConfig {
+    public static final String getAppId(){
+     return "35fdb087478a19f7";
+    }
+    public static final String getAppSecret(){
+        return "7322d8d028c29a99";
+    }
+    public static final boolean isShowLog(){
+        return TestUtil.isTest();
+    }
+}

+ 290 - 0
app/src/main/java/com/youmi/android/offer/YmPermissionUtil.java

@@ -0,0 +1,290 @@
+package com.youmi.android.offer;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.net.Uri;
+import android.provider.Settings;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.sheep.jiuyan.samllsheep.utils.G;
+
+import cde.ewd.adw.AdManager;
+import cde.ewd.adw.os.EarnPointsOrderInfo;
+import cde.ewd.adw.os.EarnPointsOrderList;
+import cde.ewd.adw.os.OffersBrowserConfig;
+import cde.ewd.adw.os.OffersManager;
+import cde.ewd.adw.os.PointsChangeNotify;
+import cde.ewd.adw.os.PointsEarnNotify;
+import cde.ewd.adw.os.PointsManager;
+
+/**
+ * Created by realicing on 2018/10/29.
+ * realicing@sina.com
+ */
+public class YmPermissionUtil implements PointsChangeNotify, PointsEarnNotify {
+    private Activity activity;
+
+    public YmPermissionUtil(Activity activity) {
+        this.activity = activity;
+    }
+
+    /**
+     * 小tips:这里的int数值不能太大,否则不会弹出请求权限提示,测试的时候,改到1000就不会弹出请求了
+     */
+    private final static int READ_PHONE_STATE_CODE = 101;
+
+    private final static int WRITE_EXTERNAL_STORAGE_CODE = 102;
+    /**
+     * 有米 Android SDK 所需要向用户申请的权限列表
+     */
+    private PermissionModel[] models = new PermissionModel[]{
+            new PermissionModel(Manifest.permission.READ_PHONE_STATE, "我们需要读取手机信息的权限来标识您的身份", READ_PHONE_STATE_CODE),
+            new PermissionModel(Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                    "我们需要您允许我们读写你的存储卡,以方便我们临时保存一些数据",
+                    WRITE_EXTERNAL_STORAGE_CODE
+            ),
+    };
+
+    /**
+     * 这里我们演示如何在Android 6.0+上运行时申请权限
+     */
+    public void checkPermissions() {
+        try {
+
+            for (PermissionModel model : models) {
+                if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(activity, model.permission)) {
+                    ActivityCompat.requestPermissions(activity, new String[]{model.permission}, model.requestCode);
+                    return;
+                }
+            }
+
+            // 到这里就表示有米所有需要的权限已经通过申请,权限已经申请就打开demo
+            showYmOffersAds();
+        } catch (Throwable e) {
+            Log.e("YoumiSdk", "", e);
+        }
+    }
+
+    public void showYmOffersAds() {
+        initYoumi();
+        setOfferBrowserConfig();
+        OffersManager.getInstance(activity).showOffersWall();
+    }
+
+    private void initYoumi() {
+        // 自v6.3.0起,所有其他代码必须在初始化接口调用之后才能生效
+        // 初始化接口,应用启动的时候调用,参数:appId, appSecret, isEnableYoumiLog
+        AdManager.getInstance(activity).init(YmConfig.getAppId(), YmConfig.getAppSecret(), YmConfig.isShowLog());
+
+        // 有米android 积分墙sdk 5.0.0之后支持定制浏览器顶部标题栏的部分UI
+        // setOfferBrowserConfig();
+
+        // 如果开发者使用积分墙的服务器回调,
+        // 1.需要告诉sdk,现在采用服务器回调
+        // 2.建议开发者传入自己系统中用户id(如:邮箱账号之类的)(请限制在50个字符串以内)
+        // 3.务必在下面的OffersManager.getInstance(this).onAppLaunch();代码之前声明使用服务器回调
+
+        // OffersManager.getInstance(this).setUsingServerCallBack(true);
+        // OffersManager.getInstance(this).setCustomUserId("user_id");
+
+        // 如果使用积分广告,请务必调用积分广告的初始化接口:
+        OffersManager.getInstance(activity).onAppLaunch();
+
+        // (可选)注册积分监听-随时随地获得积分的变动情况
+
+        PointsManager.getInstance(activity).registerNotify(this);
+
+        // (可选)注册积分订单赚取监听(sdk v4.10版本新增功能)
+        PointsManager.getInstance(activity).registerPointsEarnNotify(this);
+
+        // (可选)设置是否在通知栏显示下载相关提示。默认为true,标识开启;设置为false则关闭。(sdk v4.10版本新增功能)
+        // AdManager.getInstance(this).setIsDownloadTipsDisplayOnNotification(false);
+
+        // (可选)设置安装完成后是否在通知栏显示已安装成功的通知。默认为true,标识开启;设置为false则关闭。(sdk v4.10版本新增功能)
+        // AdManager.getInstance(this).setIsInstallationSuccessTipsDisplayOnNotification(false);
+
+        // (可选)设置是否在通知栏显示积分赚取提示。默认为true,标识开启;设置为false则关闭。
+        // 如果开发者采用了服务器回调积分的方式,那么本方法将不会生效
+        // PointsManager.getInstance(this).setEnableEarnPointsNotification(false);
+
+        // (可选)设置是否开启积分赚取的Toast提示。默认为true,标识开启;设置为false这关闭。
+        // 如果开发者采用了服务器回调积分的方式,那么本方法将不会生效
+        // PointsManager.getInstance(this).setEnableEarnPointsToastTips(false);
+
+        // 查询积分余额
+        // 从5.3.0版本起,客户端积分托管将由 int 转换为 float
+        float pointsBalance = PointsManager.getInstance(activity).queryPoints();
+        G.showToast("积分余额:" + pointsBalance);
+    }
+
+    /**
+     * 设置积分墙浏览器标题栏样式
+     */
+    private void setOfferBrowserConfig() {
+
+        // 设置标题栏——标题
+        OffersBrowserConfig.getInstance(activity).setBrowserTitleText("有米积分");
+
+        // 设置标题栏——背景颜色(ps:积分墙标题栏默认背景颜色为#FFBB34)
+        OffersBrowserConfig.getInstance(activity).setBrowserTitleBackgroundColor(Color.parseColor("#29d6fd"));
+
+        // 设置标题栏——是否显示积分墙右上角积分余额区域 true:是 false:否
+        OffersBrowserConfig.getInstance(activity).setPointsLayoutVisibility(true);
+
+        // 设置标题栏——是否显示有米的logo
+        OffersBrowserConfig.getInstance(activity).setLogoVisibility(false);
+
+    }
+
+    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+        switch (requestCode) {
+            case READ_PHONE_STATE_CODE:
+            case WRITE_EXTERNAL_STORAGE_CODE:
+                // 如果用户不允许,我们视情况发起二次请求或者引导用户到应用页面手动打开
+                if (PackageManager.PERMISSION_GRANTED != grantResults[0]) {
+
+                    // 二次请求,表现为:以前请求过这个权限,但是用户拒接了
+                    // 在二次请求的时候,会有一个“不再提示的”checkbox
+                    // 因此这里需要给用户解释一下我们为什么需要这个权限,否则用户可能会永久不在激活这个申请
+                    // 方便用户理解我们为什么需要这个权限
+                    if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permissions[0])) {
+                        new AlertDialog.Builder(activity).setTitle("权限申请")
+                                .setMessage(findPermissionExplain(permissions[0]))
+                                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
+
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        checkPermissions();
+                                    }
+                                })
+                                .show();
+                    }
+                    // 到这里就表示已经是第3+次请求,而且此时用户已经永久拒绝了,这个时候,我们引导用户到应用权限页面,让用户自己手动打开
+                    else {
+                        Toast.makeText(activity, "部分权限被拒绝获取,将会会影响后续功能的使用,建议重新打开", Toast.LENGTH_LONG).show();
+                        openAppPermissionSetting();
+                    }
+                    return;
+                }
+
+                // 到这里就表示用户允许了本次请求,我们继续检查是否还有待申请的权限没有申请
+                if (isAllRequestedPermissionGranted()) {
+                    showYmOffersAds();
+                } else {
+                    checkPermissions();
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    private String findPermissionExplain(String permission) {
+        if (models != null) {
+            for (PermissionModel model : models) {
+                if (model != null && model.permission != null && model.permission.equals(permission)) {
+                    return model.explain;
+                }
+            }
+        }
+        return null;
+    }
+
+    private boolean isAllRequestedPermissionGranted() {
+        for (final PermissionModel model : models) {
+            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(activity, model.permission)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void openAppPermissionSetting() {
+        try {
+            Intent intent =
+                    new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + activity.getPackageName()));
+            intent.addCategory(Intent.CATEGORY_DEFAULT);
+
+            // Android L 之后Activity的启动模式发生了一些变化
+            // 如果用了下面的 Intent.FLAG_ACTIVITY_NEW_TASK ,并且是 startActivityForResult
+            // 那么会在打开新的activity的时候就会立即回调 onActivityResult
+            // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            activity.startActivityForResult(intent, 123456789);
+        } catch (Throwable e) {
+            Log.e("YoumiSdk", "", e);
+        }
+    }
+
+    /**
+     * 积分余额发生变动时,就会回调本方法(本回调方法执行在UI线程中)
+     * <p/>
+     * 从5.3.0版本起,客户端积分托管将由 int 转换为 float
+     */
+    @Override
+    public void onPointBalanceChange(float pointsBalance) {
+        G.showToast("积分余额:" + pointsBalance);
+    }
+
+    /**
+     * 积分订单赚取时会回调本方法(本回调方法执行在UI线程中)
+     */
+    @Override
+    public void onPointEarn(Context context, EarnPointsOrderList list) {
+        if (list == null || list.isEmpty()) {
+            return;
+        }
+        // 遍历订单并且toast提示
+        for (int i = 0; i < list.size(); ++i) {
+            EarnPointsOrderInfo info = list.get(i);
+            Toast.makeText(activity, info.getMessage(), Toast.LENGTH_LONG).show();
+        }
+    }
+
+    public void onDestroy() {
+
+        // (可选)注销积分监听
+        // 如果在onCreate调用了PointsManager.getInstance(this).registerNotify(this)进行积分余额监听器注册,那这里必须得注销
+        PointsManager.getInstance(activity).unRegisterNotify(this);
+
+        // (可选)注销积分订单赚取监听
+        // 如果在onCreate调用了PointsManager.getInstance(this).registerPointsEarnNotify(this)进行积分订单赚取监听器注册,那这里必须得注销
+        PointsManager.getInstance(activity).unRegisterPointsEarnNotify(this);
+
+        // 回收积分广告占用的资源
+        OffersManager.getInstance(activity).onAppExit();
+    }
+
+    private static class PermissionModel {
+
+        /**
+         * 请求的权限
+         */
+        String permission;
+
+        /**
+         * 解析为什么请求这个权限
+         */
+        String explain;
+
+        /**
+         * 请求代码
+         */
+        int requestCode;
+
+        PermissionModel(String permission, String explain, int requestCode) {
+            this.permission = permission;
+            this.explain = explain;
+            this.requestCode = requestCode;
+        }
+    }
+}

+ 222 - 0
app/src/main/java/com/youmi/android/offerdemo/PermissionCheckActivity.java

@@ -0,0 +1,222 @@
+package com.youmi.android.offerdemo;
+
+import android.Manifest;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.sheep.jiuyan.samllsheep.R;
+
+/**
+ * Android 6.0 上权限分为<b>正常</b>和<b>危险</b>级别
+ * <ul>
+ * <li>正常级别权限:开发者仅仅需要在AndroidManifext.xml上声明,那么应用就会被允许拥有该权限,如:android.permission.INTERNET</li>
+ * <li>危险级别权限:开发者需要在AndroidManifext.xml上声明,并且在运行时进行申请,而且用户允许了,应用才会被允许拥有该权限,如:android.permission.WRITE_EXTERNAL_STORAGE</li>
+ * </ul>
+ * 有米的以下权限需要在Android6.0上被允许,有米广告sdk才能正常工作,开发者需要在调用有米的任何代码之前,提前让用户允许权限
+ * <ul>
+ * <li>必须申请的权限
+ * <ul>
+ * <li>android.permission.READ_PHONE_STATE</li>
+ * <li>android.permission.WRITE_EXTERNAL_STORAGE</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * @since 2015-12-10 16:36
+ */
+public class PermissionCheckActivity extends FragmentActivity {
+	
+	/**
+	 * 小tips:这里的int数值不能太大,否则不会弹出请求权限提示,测试的时候,改到1000就不会弹出请求了
+	 */
+	private final static int READ_PHONE_STATE_CODE = 101;
+	
+	private final static int WRITE_EXTERNAL_STORAGE_CODE = 102;
+	
+	/**
+	 * 有米 Android SDK 所需要向用户申请的权限列表
+	 */
+	private PermissionModel[] models = new PermissionModel[] {
+			new PermissionModel(Manifest.permission.READ_PHONE_STATE, "我们需要读取手机信息的权限来标识您的身份", READ_PHONE_STATE_CODE),
+			new PermissionModel(Manifest.permission.WRITE_EXTERNAL_STORAGE,
+					"我们需要您允许我们读写你的存储卡,以方便我们临时保存一些数据",
+					WRITE_EXTERNAL_STORAGE_CODE
+			),
+	};
+	
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		if (Build.VERSION.SDK_INT < 23) {
+			openDemo();
+			return;
+		}
+		
+		setContentView(R.layout.ym_activity_main);
+		((TextView) findViewById(R.id.tv_api)).setText("当前Android api level : " + Build.VERSION.SDK_INT);
+		checkPermissions();
+	}
+	
+	private void openDemo() {
+		startActivity(new Intent(this, YoumiOffersAdsDemo.class));
+		this.finish();
+	}
+	
+	/**
+	 * 这里我们演示如何在Android 6.0+上运行时申请权限
+	 */
+	private void checkPermissions() {
+		try {
+			
+			for (PermissionModel model : models) {
+				if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, model.permission)) {
+					ActivityCompat.requestPermissions(this, new String[] { model.permission }, model.requestCode);
+					return;
+				}
+			}
+			
+			// 到这里就表示有米所有需要的权限已经通过申请,权限已经申请就打开demo
+			openDemo();
+		} catch (Throwable e) {
+			Log.e("YoumiSdk", "", e);
+		}
+	}
+	
+	@Override
+	public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+		super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+		switch (requestCode) {
+		
+		case READ_PHONE_STATE_CODE:
+		case WRITE_EXTERNAL_STORAGE_CODE:
+			// 如果用户不允许,我们视情况发起二次请求或者引导用户到应用页面手动打开
+			if (PackageManager.PERMISSION_GRANTED != grantResults[0]) {
+				
+				// 二次请求,表现为:以前请求过这个权限,但是用户拒接了
+				// 在二次请求的时候,会有一个“不再提示的”checkbox
+				// 因此这里需要给用户解释一下我们为什么需要这个权限,否则用户可能会永久不在激活这个申请
+				// 方便用户理解我们为什么需要这个权限
+				if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
+					new AlertDialog.Builder(this).setTitle("权限申请")
+					                             .setMessage(findPermissionExplain(permissions[0]))
+					                             .setPositiveButton("确定", new DialogInterface.OnClickListener() {
+						
+						                             @Override
+						                             public void onClick(DialogInterface dialog, int which) {
+							                             checkPermissions();
+						                             }
+					                             })
+					                             .show();
+				}
+				// 到这里就表示已经是第3+次请求,而且此时用户已经永久拒绝了,这个时候,我们引导用户到应用权限页面,让用户自己手动打开
+				else {
+					Toast.makeText(this, "部分权限被拒绝获取,将会会影响后续功能的使用,建议重新打开", Toast.LENGTH_LONG).show();
+					openAppPermissionSetting(123456789);
+				}
+				return;
+			}
+			
+			// 到这里就表示用户允许了本次请求,我们继续检查是否还有待申请的权限没有申请
+			if (isAllRequestedPermissionGranted()) {
+				openDemo();
+			} else {
+				checkPermissions();
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	
+	private String findPermissionExplain(String permission) {
+		if (models != null) {
+			for (PermissionModel model : models) {
+				if (model != null && model.permission != null && model.permission.equals(permission)) {
+					return model.explain;
+				}
+			}
+		}
+		return null;
+	}
+	
+	private boolean isAllRequestedPermissionGranted() {
+		for (final PermissionModel model : models) {
+			if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, model.permission)) {
+				return false;
+			}
+		}
+		return true;
+	}
+	
+	@Override
+	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+		switch (requestCode) {
+		
+		case 123456789:
+			if (isAllRequestedPermissionGranted()) {
+				openDemo();
+			} else {
+				Toast.makeText(this, "部分权限被拒绝获取,退出", Toast.LENGTH_LONG).show();
+				this.finish();
+			}
+			break;
+		default:
+			super.onActivityResult(requestCode, resultCode, data);
+		}
+	}
+	
+	private boolean openAppPermissionSetting(int requestCode) {
+		try {
+			Intent intent =
+					new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + this.getPackageName()));
+			intent.addCategory(Intent.CATEGORY_DEFAULT);
+			
+			// Android L 之后Activity的启动模式发生了一些变化
+			// 如果用了下面的 Intent.FLAG_ACTIVITY_NEW_TASK ,并且是 startActivityForResult
+			// 那么会在打开新的activity的时候就会立即回调 onActivityResult
+			// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+			
+			startActivityForResult(intent, requestCode);
+			return true;
+		} catch (Throwable e) {
+			Log.e("YoumiSdk", "", e);
+		}
+		return false;
+	}
+	
+	private static class PermissionModel {
+		
+		/**
+		 * 请求的权限
+		 */
+		String permission;
+		
+		/**
+		 * 解析为什么请求这个权限
+		 */
+		String explain;
+		
+		/**
+		 * 请求代码
+		 */
+		int requestCode;
+		
+		PermissionModel(String permission, String explain, int requestCode) {
+			this.permission = permission;
+			this.explain = explain;
+			this.requestCode = requestCode;
+		}
+	}
+}

+ 378 - 0
app/src/main/java/com/youmi/android/offerdemo/YoumiOffersAdsDemo.java

@@ -0,0 +1,378 @@
+package com.youmi.android.offerdemo;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.sheep.jiuyan.samllsheep.R;
+import com.youmi.android.offer.YmConfig;
+
+import cde.ewd.adw.AdManager;
+import cde.ewd.adw.listener.Interface_ActivityListener;
+import cde.ewd.adw.listener.OffersWallDialogListener;
+import cde.ewd.adw.os.EarnPointsOrderInfo;
+import cde.ewd.adw.os.EarnPointsOrderList;
+import cde.ewd.adw.os.OffersBrowserConfig;
+import cde.ewd.adw.os.OffersManager;
+import cde.ewd.adw.os.PointsChangeNotify;
+import cde.ewd.adw.os.PointsEarnNotify;
+import cde.ewd.adw.os.PointsManager;
+import cde.ewd.adw.onlineconfig.OnlineConfigCallBack;
+import cde.ewd.adw.onlineconfig.ntp.NtpResultListener;
+
+import java.util.Locale;
+
+public class YoumiOffersAdsDemo extends Activity
+		implements OnClickListener, PointsChangeNotify, PointsEarnNotify {
+	
+	/**
+	 * 显示积分余额的控件
+	 */
+	TextView mTextViewPoints;
+	
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.ym_activity_offers);
+		
+		mTextViewPoints = (TextView) findViewById(R.id.pointsBalance);
+		findViewById(R.id.btn_show_offerswall).setOnClickListener(this);
+		findViewById(R.id.btn_show_offerswall_dialog).setOnClickListener(this);
+		findViewById(R.id.btn_award_points).setOnClickListener(this);
+		findViewById(R.id.btn_spend_points).setOnClickListener(this);
+		findViewById(R.id.btn_get_online_config).setOnClickListener(this);
+		findViewById(R.id.btn_check_reach_ntp_time).setOnClickListener(this);
+		findViewById(R.id.btn_check_ad_config).setOnClickListener(this);
+		
+		showDemoInfo();
+		
+		initYoumi();
+	}
+	
+	private void initYoumi() {
+		// 自v6.3.0起,所有其他代码必须在初始化接口调用之后才能生效
+		// 初始化接口,应用启动的时候调用,参数:appId, appSecret, isEnableYoumiLog
+		AdManager.getInstance(this).init(YmConfig.getAppId(), YmConfig.getAppSecret(), YmConfig.isShowLog());
+		
+		// 有米android 积分墙sdk 5.0.0之后支持定制浏览器顶部标题栏的部分UI
+		// setOfferBrowserConfig();
+		
+		// 如果开发者使用积分墙的服务器回调,
+		// 1.需要告诉sdk,现在采用服务器回调
+		// 2.建议开发者传入自己系统中用户id(如:邮箱账号之类的)(请限制在50个字符串以内)
+		// 3.务必在下面的OffersManager.getInstance(this).onAppLaunch();代码之前声明使用服务器回调
+		
+		// OffersManager.getInstance(this).setUsingServerCallBack(true);
+		// OffersManager.getInstance(this).setCustomUserId("user_id");
+		
+		// 如果使用积分广告,请务必调用积分广告的初始化接口:
+		OffersManager.getInstance(this).onAppLaunch();
+		
+		// (可选)注册积分监听-随时随地获得积分的变动情况
+		PointsManager.getInstance(this).registerNotify(this);
+		
+		// (可选)注册积分订单赚取监听(sdk v4.10版本新增功能)
+		PointsManager.getInstance(this).registerPointsEarnNotify(this);
+		
+		// (可选)设置是否在通知栏显示下载相关提示。默认为true,标识开启;设置为false则关闭。(sdk v4.10版本新增功能)
+		// AdManager.getInstance(this).setIsDownloadTipsDisplayOnNotification(false);
+		
+		// (可选)设置安装完成后是否在通知栏显示已安装成功的通知。默认为true,标识开启;设置为false则关闭。(sdk v4.10版本新增功能)
+		// AdManager.getInstance(this).setIsInstallationSuccessTipsDisplayOnNotification(false);
+		
+		// (可选)设置是否在通知栏显示积分赚取提示。默认为true,标识开启;设置为false则关闭。
+		// 如果开发者采用了服务器回调积分的方式,那么本方法将不会生效
+		// PointsManager.getInstance(this).setEnableEarnPointsNotification(false);
+		
+		// (可选)设置是否开启积分赚取的Toast提示。默认为true,标识开启;设置为false这关闭。
+		// 如果开发者采用了服务器回调积分的方式,那么本方法将不会生效
+		// PointsManager.getInstance(this).setEnableEarnPointsToastTips(false);
+		
+		// 查询积分余额
+		// 从5.3.0版本起,客户端积分托管将由 int 转换为 float
+		float pointsBalance = PointsManager.getInstance(this).queryPoints();
+		mTextViewPoints.setText("积分余额:" + pointsBalance);
+	}
+	
+	/**
+	 * 退出时回收资源
+	 */
+	@Override
+	protected void onDestroy() {
+		super.onDestroy();
+		
+		// (可选)注销积分监听
+		// 如果在onCreate调用了PointsManager.getInstance(this).registerNotify(this)进行积分余额监听器注册,那这里必须得注销
+		PointsManager.getInstance(this).unRegisterNotify(this);
+		
+		// (可选)注销积分订单赚取监听
+		// 如果在onCreate调用了PointsManager.getInstance(this).registerPointsEarnNotify(this)进行积分订单赚取监听器注册,那这里必须得注销
+		PointsManager.getInstance(this).unRegisterPointsEarnNotify(this);
+		
+		// 回收积分广告占用的资源
+		OffersManager.getInstance(this).onAppExit();
+	}
+	
+	/**
+	 * 积分余额发生变动时,就会回调本方法(本回调方法执行在UI线程中)
+	 * <p/>
+	 * 从5.3.0版本起,客户端积分托管将由 int 转换为 float
+	 */
+	@Override
+	public void onPointBalanceChange(float pointsBalance) {
+		mTextViewPoints.setText("积分余额:" + pointsBalance);
+	}
+	
+	/**
+	 * 积分订单赚取时会回调本方法(本回调方法执行在UI线程中)
+	 */
+	@Override
+	public void onPointEarn(Context context, EarnPointsOrderList list) {
+		if (list == null || list.isEmpty()) {
+			return;
+		}
+		// 遍历订单并且toast提示
+		for (int i = 0; i < list.size(); ++i) {
+			EarnPointsOrderInfo info = list.get(i);
+			Toast.makeText(this, info.getMessage(), Toast.LENGTH_LONG).show();
+		}
+	}
+	
+	@Override
+	public void onClick(View arg0) {
+		switch (arg0.getId()) {
+		
+		// 展示全屏的积分墙界面
+		case R.id.btn_show_offerswall:
+			
+			// 调用方式一:直接打开全屏积分墙
+			// OffersManager.getInstance(this).showOffersWall();
+			
+			// 调用方式二:直接打开全屏积分墙,并且监听积分墙退出的事件onDestory
+			OffersManager.getInstance(this).showOffersWall(new Interface_ActivityListener() {
+				
+				/**
+				 * 当积分墙销毁的时候,即积分墙的Activity调用了onDestory的时候回调
+				 */
+				@Override
+				public void onActivityDestroy(Context context) {
+					Toast.makeText(context, "全屏积分墙退出了", Toast.LENGTH_SHORT).show();
+				}
+			});
+			
+			break;
+		
+		// 展示对话框的积分墙界面(本方法支持多种重载格式,开发者可以参考文档或者使用代码提示快捷键来了解)
+		case R.id.btn_show_offerswall_dialog:
+			OffersManager.getInstance(this).showOffersWallDialog(this, new OffersWallDialogListener() {
+				
+				@Override
+				public void onDialogClose() {
+					Toast.makeText(YoumiOffersAdsDemo.this, "积分墙对话框关闭了", Toast.LENGTH_SHORT).show();
+				}
+			});
+			break;
+		
+		// 奖励10积分, 注:调用本方法后,积分余额马上变更,可留意onPointBalanceChange是不是被调用了
+		// 从5.3.0版本起,客户端积分托管将由 int 转换为 float
+		case R.id.btn_award_points:
+			PointsManager.getInstance(this).awardPoints(10.0f);
+			break;
+		
+		// 消费20积分, 注:调用本方法后,积分余额马上变更,可留意onPointBalanceChange是不是被调用了
+		// 从5.3.0版本起,客户端积分托管将由 int 转换为 float
+		case R.id.btn_spend_points:
+			PointsManager.getInstance(this).spendPoints(20.0f);
+			break;
+		
+		// 获取在线参数
+		case R.id.btn_get_online_config:
+			Toast.makeText(this, "获取在线参数中...", Toast.LENGTH_LONG).show();
+			
+			// 注意:这里获取的在线参数的key为 :isOpen,为演示的key , 开发者需要将key替换为开发者在自己有米后台上面设置的key
+			AdManager.getInstance(this).asyncGetOnlineConfig("isOpen", new OnlineConfigCallBack() {
+				/**
+				 * 获取在线参数成功就会回调本方法(本回调方法执行在UI线程中)
+				 */
+				@Override
+				public void onGetOnlineConfigSuccessful(String key, String value) {
+					// 获取在线参数成功
+					Toast.makeText(YoumiOffersAdsDemo.this,
+							String.format("在线参数获取结果:\nkey=%s, value=%s", key, value),
+							Toast.LENGTH_LONG
+					)
+					     .show();
+					
+					// //
+					// 开发者在这里可以判断一下获取到的value值,然后设置一个boolean值并将其保存在文件中,每次调用广告之前从文件中获取boolean
+					// 值并判断一下是否可以展示广告
+					// if (key.equals("isOpen")) {
+					// if (value.equals("1")) {
+					// // 如果满足开发者自己的定义:如示例中如果key=isOpen value=1 则定义为开启广告
+					// // 则将flag(boolean值)设置为true,然后每次调用广告代码之前都判断一下flag,如果flag为true则执行展示广告的代码
+					// flag = true;
+					// // 写入文件 ...
+					// }
+					// }
+					
+				}
+				
+				/**
+				 * 获取在线参数失败就会回调本方法(本回调方法执行在UI线程中)
+				 */
+				@Override
+				public void onGetOnlineConfigFailed(String key) {
+					// 获取在线参数失败,可能原因有:键值未设置或为空、网络异常、服务器异常
+					Toast.makeText(YoumiOffersAdsDemo.this,
+							String.format("在线参数获取结果:\n获取在线key=%s失败!\n具体失败原因请查看Log,Log标签:YoumiSdk", key),
+							Toast.LENGTH_LONG
+					).show();
+				}
+			});
+			break;
+		
+		// 检查是否达到指定的网络时间——ntp
+		// 使用场合:开发者可以指定一个日期,然后到达该日期之后才开启广告
+		// 具体做法:当获取到结果的时候,可以把结果(boolean)保存在文件中,然后每次启动的时候获取文件的内容,然后根据内容来判断是否开启广告
+		case R.id.btn_check_reach_ntp_time:
+			
+			// 检查现在是否到达2014年11月12号 GTM+8
+			final int targetYear = 2014;
+			final int targetMonth = 11;
+			final int targetMonthDay = 15;
+			
+			// 这里演示异步方法的使用,同步方法的的使用请查看文档
+			AdManager.getInstance(this)
+			                  .asyncCheckIsReachNtpTime(targetYear,
+					                  targetMonth,
+					                  targetMonthDay,
+					                  new NtpResultListener() {
+						
+						                  /**
+						                   * 当获取到网络时间时,会回调本方法(本方法执行在UI线程中)
+						                   */
+						                  @Override
+						                  public void onCheckNtpFinish(boolean result) {
+							                  String logText = String.format(Locale.getDefault(),
+									                  "是否到达日期: %d-%d-%d " + "%s",
+									                  targetYear,
+									                  targetMonth,
+									                  targetMonthDay,
+									                  result ? "是" : "否"
+							                  );
+							                  Log.i("ntp_", logText);
+							                  Toast.makeText(YoumiOffersAdsDemo.this, logText, Toast.LENGTH_LONG).show();
+						                  }
+					                  }
+			                  );
+			
+			break;
+		
+		// 检查积分墙广告配置
+		case R.id.btn_check_ad_config:
+			checkConfig();
+			break;
+		
+		default:
+			break;
+		}
+	}
+	
+	/**
+	 * 检查广告配置
+	 */
+	private void checkConfig() {
+		StringBuilder sb = new StringBuilder();
+		
+		addTextToSb(sb,
+				OffersManager.getInstance(this).checkOffersAdConfig() ? "广告配置结果:正常" :
+						"广告配置结果:异常,具体异常请查看Log,Log标签:YoumiSdk"
+		);
+		addTextToSb(sb, "%s服务器回调", OffersManager.getInstance(this).isUsingServerCallBack() ? "已经开启" : "没有开启");
+		addTextToSb(sb,
+				"%s通知栏下载相关的通知",
+				AdManager.getInstance(this).isDownloadTipsDisplayOnNotification() ? "已经开启" : "没有开启"
+		);
+		addTextToSb(sb,
+				"%s通知栏安装成功的通知",
+				AdManager.getInstance(this).isInstallationSuccessTipsDisplayOnNotification() ? "已经开启" : "没有开启"
+		);
+		addTextToSb(sb,
+				"%s通知栏赚取积分的提示",
+				PointsManager.getInstance(this).isEnableEarnPointsNotification() ? "已经开启" : "没有开启"
+		);
+		addTextToSb(sb,
+				"%s积分赚取的Toast提示",
+				PointsManager.getInstance(this).isEnableEarnPointsToastTips() ? "已经开启" : "没有开启"
+		);
+		
+		new AlertDialog.Builder(this).setTitle("检查结果")
+		                             .setMessage(sb.toString())
+		                             .setPositiveButton("确定", new DialogInterface.OnClickListener() {
+			
+			                             @Override
+			                             public void onClick(DialogInterface dialog, int which) {
+				                             dialog.dismiss();
+			                             }
+			
+		                             })
+		                             .create()
+		                             .show();
+	}
+	
+	/**
+	 * 格式化字符串
+	 */
+	private void addTextToSb(StringBuilder sb, String format, Object... args) {
+		sb.append(String.format(format, args));
+		sb.append(System.getProperty("line.separator"));
+	}
+	
+	/**
+	 * 设置积分墙浏览器标题栏样式
+	 */
+	private void setOfferBrowserConfig() {
+		
+		// 设置标题栏——标题
+		OffersBrowserConfig.getInstance(this).setBrowserTitleText("秒取积分");
+		
+		// 设置标题栏——背景颜色(ps:积分墙标题栏默认背景颜色为#FFBB34)
+		OffersBrowserConfig.getInstance(this).setBrowserTitleBackgroundColor(Color.BLUE);
+		
+		// 设置标题栏——是否显示积分墙右上角积分余额区域 true:是 false:否
+		OffersBrowserConfig.getInstance(this).setPointsLayoutVisibility(true);
+		
+		// 设置标题栏——是否显示有米的logo
+		OffersBrowserConfig.getInstance(this).setLogoVisibility(false);
+		
+	}
+	
+	/**
+	 * 显示demo的一些详细信息
+	 */
+	private void showDemoInfo() {
+		try {
+			PackageInfo packageInfo = getPackageManager().getPackageInfo(this.getPackageName(), 0);
+			String message = String.format(Locale.getDefault(),
+					"vc: %d, vn: %s, install time: %3$tY-%3$tm-%3$td %3$tH:%3$tM:%3$tS",
+					packageInfo.versionCode,
+					packageInfo.versionName,
+					packageInfo.firstInstallTime
+			);
+			((TextView) findViewById(R.id.tv_version)).setText(message);
+		} catch (PackageManager.NameNotFoundException e) {
+			e.printStackTrace();
+		}
+		
+	}
+}

+ 6 - 0
app/src/main/res/drawable/ym_buttonbg.xml

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

+ 25 - 0
app/src/main/res/layout/ym_activity_main.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView android:id="@+id/offersTestItems"
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:background="@color/global_bg"
+	>
+
+	<LinearLayout
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:orientation="vertical"
+		>
+
+		<TextView
+			android:id="@+id/tv_api"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_margin="10dp"
+			android:textAppearance="?android:attr/textAppearanceSmall"
+			android:textColor="@android:color/darker_gray"
+			/>
+	</LinearLayout >
+
+</ScrollView >

+ 73 - 0
app/src/main/res/layout/ym_activity_offers.xml

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView android:id="@+id/offersTestItems"
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:background="@color/global_bg"
+	>
+
+	<LinearLayout
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:orientation="vertical"
+		>
+
+		<TextView
+			android:id="@+id/pointsBalance"
+			style="@style/TextViewStyle"
+			android:textColor="@color/points"
+			/>
+
+		<Button
+			android:id="@+id/btn_show_offerswall"
+			style="@style/BtnStyle"
+			android:text="@string/btn_show_offerswall"
+			/>
+
+		<Button
+			android:id="@+id/btn_show_offerswall_dialog"
+			style="@style/BtnStyle"
+			android:text="@string/btn_show_offerswall_dialog"
+			/>
+
+		<Button
+			android:id="@+id/btn_award_points"
+			style="@style/BtnStyle"
+			android:text="@string/btn_award_points"
+			/>
+
+		<Button
+			android:id="@+id/btn_spend_points"
+			style="@style/BtnStyle"
+			android:text="@string/btn_spend_points"
+			/>
+
+		<Button
+			android:id="@+id/btn_get_online_config"
+			style="@style/BtnStyle"
+			android:text="@string/btn_get_online_config"
+			/>
+
+		<Button
+			android:id="@+id/btn_check_reach_ntp_time"
+			style="@style/BtnStyle"
+			android:text="@string/btn_check_reach_ntp_time"
+			/>
+
+		<Button
+			android:id="@+id/btn_check_ad_config"
+			style="@style/BtnStyle"
+			android:text="@string/btn_check_ad_config"
+			/>
+
+		<TextView
+			android:id="@+id/tv_version"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_margin="10dp"
+			android:textAppearance="?android:attr/textAppearanceSmall"
+			android:textColor="@android:color/darker_gray"
+			/>
+	</LinearLayout >
+
+</ScrollView >

+ 5 - 0
app/src/main/res/values/ym_colors.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources >
+	<color name="global_bg">#5a5a5a</color>
+	<color name="points">#87cefa</color>
+</resources >

+ 13 - 0
app/src/main/res/values/ym_strings.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="action_settings">设置</string>
+    <string name="btn_show_offerswall">展示积分墙(全屏)</string>
+    <string name="btn_show_offerswall_dialog">展示积分墙(对话框)</string>
+    <string name="btn_award_points">奖励10积分</string>
+    <string name="btn_spend_points">消费20积分</string>
+    <string name="btn_get_online_config">获取有米在线参数</string>
+    <string name="btn_check_reach_ntp_time">是否达到指定网络时间</string>
+    <string name="btn_check_ad_config">检查广告配置</string>
+
+</resources>

+ 16 - 0
app/src/main/res/values/ym_styles.xml

@@ -0,0 +1,16 @@
+<resources >
+
+	<style name="TextViewStyle" >
+		<item name="android:layout_width" >fill_parent</item >
+		<item name="android:layout_height" >wrap_content</item >
+		<item name="android:layout_margin" >10dp</item >
+		<item name="android:textAppearance" >?android:attr/textAppearanceLarge</item >
+	</style >
+
+	<style name="BtnStyle"
+	       parent="TextViewStyle" >
+		<item name="android:background" >@drawable/ym_buttonbg</item >
+		<item name="android:textAppearance" >?android:attr/textAppearanceMedium</item >
+	</style >
+
+</resources >

+ 10 - 0
app/src/main/res/xml/file_paths.xml

@@ -7,4 +7,14 @@
     <external-path path="." name="external_storage_root"/>
     <external-path path="" name="Download"/>
     <external-path name="download" path="."/>
+    <!--
+    有米sdk会将apk优先下载在sd卡中,如果sd卡不能使用,则会使用应用私有缓存目录context.getCache()
+    因此需要开发者配置下面两个路径方便有米sdk在下载完apk之后启动apk的安装页面
+    <cache-path
+        name="apk1"
+        path="." />
+    -->
+    <external-path
+        name="apk2"
+        path="." />
 </resources>