提醒用户完成流量配置功能的实现

背景描述

  • sdk支持的流量管理功能需要配置运营商省份和品牌两个信息后才可以生效
  • 在双卡的场景下,由于sdk的问题,假如卡槽1上的卡做过配置,卡槽2的卡在未正确配置的情况下,sdk会自动分配卡槽1的运营商配置信息给卡槽2,导致卡槽2出现无法通过短信校准流量的问题
  • 假如两张卡都进行过运营商配置,用户手工交换两张卡的位置,sdk无法自动检查这种情况,不能及时更新sim卡配置信息,导致流量校验等功能失效

监听sim卡插拔并且提醒用户发生配置变更的解决方案

<receiver android:name="com.oneplus.security.network.simcard.SimcardStateChangeReceiver"
          android:exported="true"
          android:enabled="true" >
    <intent-filter>
        <action android:name="android.intent.action.SIM_STATE_CHANGED"/>
    </intent-filter>
</receiver>
@Override
public void onReceive (Context context, Intent intent) {
    String action = intent.getAction();
    if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
        String state = intent.getStringExtra(SimStateListener.SIM_STATE_KEY);
        if (SimStateListener.SS_ABSENT.equals(state)) {
            SimcardStateManager.setShouldAlertSimcardHasPopedOut(context, true,
                    SimcardDataModelInterface.SIM_CARD_ONE_INDEX);
            SimcardStateManager.setShouldAlertSimcardHasPopedOut(context, true,
                    SimcardDataModelInterface.SIM_CARD_TWO_INDEX);
        }
    }
}
  • 注册静态广播,监听sim卡插拔状态的变化,发生sim卡absent事件时,设置需要提醒用户配置流量标识(alert_data_change_flag)为true,每次启动流量管理界面时,都弹出对话框提示,假如用户跟随对话框提示的指引进入配置页面,则认为用户已经正确做完配置,重置标志位alert_data_change_flag为false
  • 这个方案的问题
    • 假如用户曾经做过正确的配置,只是因为某些原因重插拔卡,提示会造成干扰
    • 监听SS_ABSENT的方法不合适,因为手机重新开机时,sim卡会走一遍从SS_ABSENT过渡到SS_READY的过程,因为我们注册了静态广播,即使用户没做过任何插拔卡动作,也会触发提醒
  • 这个问题根本上是解决怎么保存用户配置问题,而不是插拔卡的问题,以监听插拔卡来设置标记的方式,只是针对现象做补救,而不解决根本问题

怎么保存用户的配置信息
找到唯一标识sim卡的id信息
咨询其他同事,可以用sim卡的subId来做标识,在一台手机上,每次插入一张新的sim卡,手机会给这张卡一个递增的subId,即便以后发生过换卡等操作,再次使用这张卡时,也会使用之前保存过的subId来标识旧的sim卡,所以方案演变成

以sim卡的subId为key做永久存储,通过检查一个subId对应的value有效性的方式决定要不要提示用户重新配置

  • 在用户配置运营商信息时,获取被设置卡的subId,以之为key做永久存储,参考CarrierConfigFragment.java
@Override
public boolean onPreferenceChange (Preference preference, Object newValue) {
    if (preference == mProvinceSelection) {
        String newProvince = String.valueOf(newValue);
        if (null != mOperatorPrefModel) {
            mOperatorPrefModel.setProvince(newProvince);
            SimcardInfoSaver.saveSimcardProvinceBySubId(getActivity(), mSubId, newProvince);
        }
        return true;
    } else if (preference == mBrandSelection) {
        String newBrand = String.valueOf(newValue);
        if (null != mOperatorPrefModel) {
            mOperatorPrefModel.setBrand(newBrand);
            SimcardInfoSaver.saveSimcardBrandBySubId(getActivity(), mSubId, newBrand);
        }
        return true;
    }
    return false;
}
  • 依旧监听sim卡插拔状态的监听,避免做不必要的更新检查
  • 在需要检查的时候,根据卡槽上某张卡的subId获取province和brand等信息,做有效性检查,有效重新设置,无效发出警告,以下代码在流量管理的主界面管理代码中
private boolean alertSimcardOneIfNecessary () {
    return getShouldAlertSimcardChange(SimcardDataModelInterface.SIM_CARD_ONE_INDEX, new SimcardProvinceAndBrandSetter() {
        @Override
        public void setProvinceAndBrand (String province, String brand) {
            if (null != mOperatorDataModelSimOne) {
                mOperatorDataModelSimOne.setProvince(SimcardDataModelInterface
                        .SIM_CARD_ONE_INDEX, province);
                mOperatorDataModelSimOne.setOperatorBrand(SimcardDataModelInterface
                        .SIM_CARD_ONE_INDEX, brand);
            }
        }
    });
}
private boolean alertSimcardTwoIfNecessary() {
    return getShouldAlertSimcardChange(SimcardDataModelInterface.SIM_CARD_TWO_INDEX, new SimcardProvinceAndBrandSetter() {
        @Override
        public void setProvinceAndBrand (String province, String brand) {
            if (null != mOperatorDataModelSimTwo) {
                mOperatorDataModelSimTwo.setProvince(SimcardDataModelInterface
                        .SIM_CARD_TWO_INDEX, province);
                mOperatorDataModelSimTwo.setOperatorBrand(SimcardDataModelInterface
                        .SIM_CARD_TWO_INDEX, brand);
            }
        }
    });
}
private boolean getShouldAlertSimcardChange (int slotId, final SimcardProvinceAndBrandSetter
        setter) {
    if (null == mSimcardDataModel) {
        return false;
    }
    final Context c = getActivity();
    if (mCurrentDataSlotId == SimcardDataModelInterface.INVALID_SIM_SLOT_ID) {
        return false;
    }
    if (!SimcardStateManager.getShouldAlertSimcardHasPopedOut(getActivity(), slotId)) {
        return false;
    }
    boolean shouldAlertSimcardChangeDialog = false;
    if (mSimcardDataModel.isSlotSimInserted(slotId)
            && mSimcardDataModel.isSlotOperatorSupportedBySdk(slotId)) {
        int subId = SimcardDataModel.staticGetSubIdBySlotId(slotId);
        String province = SimcardInfoSaver.getSimcardProvinceBySubId(getActivity(), subId);
        String brand = SimcardInfoSaver.getSimcardBrandBySubId(getActivity(), subId);
        if (SimcardInfoSaver.SIMCARD_BRAND_INVALID_VALUE.equals(brand)
                || SimcardInfoSaver.SIMCARD_PROVINCE_INVALID_VALUE.equals(province)) {
            LogUtils.LogD(TAG, "alert slot1 error " + brand + " " + province);
            if (SimcardStateManager.getShouldAlertSimcardHasPopedOut(getActivity(), slotId)) {
                showReconfigSimcardAlert(c, slotId);
                shouldAlertSimcardChangeDialog = true;
            } else {
                shouldAlertSimcardChangeDialog = false;
            }
        } else {
            LogUtils.LogD(TAG, "detect simcard change and reset sdk information on slot 1.");
            setter.setProvinceAndBrand(province, brand);
        }
    }
    return shouldAlertSimcardChangeDialog;
}
private interface SimcardProvinceAndBrandSetter {
    void setProvinceAndBrand(String province, String brand);
}
private void showReconfigSimcardAlert (final Context c, final int slotId) {
    AlertDialog.Builder builder = new AlertDialog.Builder(c);
    builder.setCancelable(true);
    StringBuilder sb = new StringBuilder();
    sb.append(getSimCardDescriptions(slotId));
    sb.append("\r\n");
    sb.append(c.getText(R.string.detect_simcard_change_please_confirm_config));
    builder.setMessage(sb.toString());
    builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
        @Override
        public void onClick (DialogInterface dialog, int which) {
            startSpecificTrafficConfigSettingsActivity(slotId);
        }
    });
    builder.create().show();
}
  • 代码的触发点有两个位置,一个是进入流量管理界面的动画结束之后,另一个是点击流量校准按钮的时候
@Override
public void pageInAnim () {
    super.pageInAnim();
    mDataTopView.animtionCircle(true);
    if (null != mOperatorDataModel) {
        mOperatorDataModel.requesetPkgMonthlyUsageAndTotalInByte(mCurrentDataSlotId);
    }
    alertSimcardOneIfNecessary();
    alertSimcardTwoIfNecessary();
}
mSimDataUsageQueryButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick (View v) {
        ...
        if (SimcardDataModelInterface.SIM_CARD_ONE_INDEX == mCurrentDataSlotId) {
            if (alertSimcardOneIfNecessary()) {
                return;
            }
        } else if (SimcardDataModelInterface.SIM_CARD_TWO_INDEX == mCurrentDataSlotId) {
            if (alertSimcardTwoIfNecessary()) {
                return;
            }
        } else {
            // CurrentDataSlotId is invalid, should do nothing but return. actually, in
            // this circumstances, data calibrate button is invisible.
            return;
        }
        ...
    }
};

测试建议及其他

  • 非sdk支持的运营商卡,不会产生自动配置省份和品牌的行为,因为本身就不需要设置 比如小米卡
  • 单张卡插入 从未配置过的sim卡 活动到流量页或者点击流量校准按钮
  • 会弹出需要配置的提示框 点击边缘可以退出提示框使用其他功能 但是重复步骤2会继续提示
  • 有两种方法可以终止提示 a.点击提示框的确定跳转到设置界面 b.点击流量套餐配置跳转到设置界面
  • 已经配置过的sim卡,如果没有做过清除用户数据的操作,即使交换卡位,预期可以自动完成sim卡配置,不会弹出提示框,手工进入 流量套餐配置预期可以查看到正确的配置,流量校准使用正常
  • 双卡的情况下,如果两张卡都配置过,无论是否交换卡位,预期不会弹提示框,进入对应卡槽的配置界面,预期省份及品牌信息显示正确,功能正常
  • 双卡情况下,两张卡均未配置过,会提示用户进行配置
  • 双卡,一张配置、一张未配置,且都被sdk支持,即使交换卡位,预期已配置的卡显示正确,功能正常,未配置过的卡会按照2的逻辑弹出提示
  • 已配置过的卡且或者未配置过的卡进行过4中操作,重启手机不会重复弹框
  • 未配置过的卡并且未进行过4中操作,重启手机,滑动到流量界面,点击校准按钮,都会弹框提示

最终效果

已经配置过的sim卡,可以正常识别并进行重新设置,不会频繁骚扰用户

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容