/* * Copyright 2012 The Stanford MobiSocial Laboratory * * 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 mobisocial.musubi.ui.fragments; import java.io.IOException; import java.util.HashSet; import mobisocial.metrics.MusubiMetrics; import mobisocial.musubi.App; import mobisocial.musubi.R; import org.apache.commons.io.IOUtils; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnKeyListener; import android.content.Intent; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.SupportActivity; import android.text.Html; import android.text.util.Linkify; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TabHost; import android.widget.TabHost.TabSpec; import android.widget.TabWidget; import android.widget.TextView; public class EulaFragment extends DialogFragment { public interface Callback { void eulaResult(boolean accepted); } public static final String TAG = "EulaFragment"; public static final String PREFS_NAME = "eula"; public static final String EULA_VERSION_KEY = "version"; //bump me and update the copy bundled in the assests directory public static final int CURRENT_VERSION = 0; public static final String EULA_LOCAL_ASSET = "eula.txt"; public static final String EULA_WEB_URL = "http://mobisocial.stanford.edu/musubi/public/#/eula"; public static final String PRIVACY_LOCAL_ASSET = "privacypolicy.txt"; public static final String PRIVACY_WEB_URL = "http://mobisocial.stanford.edu/musubi/public/#/privacy"; public static final int EULA_WEB_DELAY = 12 * 1000; public static final String EULA_MAIL_SUBJECT = "Musubi Usage Agreements"; private Button mAcceptButton; private Button mRejectButton; private Button mEmailButton; private CheckBox mAcceptedCheckbox; private ScrollView mEulaScroll; private LinearLayout mLoading; private TextView mEulaBodyView; private TextView mPrivacyBodyView; private LinearLayout mEulaAcceptArea; private Button mDismissButton; private Activity mActivity; private TabHost mTabs; private String mEulaTxt; private String mPrivacyTxt; private boolean mAccepted = false; private boolean mRequired; public EulaFragment() { //in case something weird happens //the default is true mRequired = true; } public EulaFragment(boolean required) { mRequired = required; } public static boolean needsEULA(Context context) { SharedPreferences prefs = context.getSharedPreferences(EulaFragment.PREFS_NAME, 0); int old_version = prefs.getInt(EulaFragment.EULA_VERSION_KEY, -1); if(old_version < 0 || old_version < EulaFragment.CURRENT_VERSION) { return true; } return false; } public static void acceptedEULA(Context context) { SharedPreferences prefs = context.getSharedPreferences(EulaFragment.PREFS_NAME, 0); prefs.edit().putInt(EulaFragment.EULA_VERSION_KEY, EulaFragment.CURRENT_VERSION).commit(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void onAttach(SupportActivity activity) { super.onAttach(activity); mActivity = activity.asActivity(); } class AgreementLoader extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { mEulaScroll.setVisibility(View.GONE); mLoading.setVisibility(View.VISIBLE); } @Override protected Void doInBackground(Void... params) { if(mEulaTxt == null) { try { mEulaTxt = IOUtils.toString(mActivity.getResources().getAssets().open(EULA_LOCAL_ASSET)); } catch (IOException e) { Log.e(TAG, "failed to set text on eula view", e); mEulaTxt = "Visit " + EULA_WEB_URL; Linkify.addLinks(mEulaBodyView, Linkify.ALL); } } if(mPrivacyTxt == null) { try { mPrivacyTxt = IOUtils.toString(mActivity.getResources().getAssets().open(PRIVACY_LOCAL_ASSET)); } catch (IOException e) { Log.e(TAG, "failed to set text on eula view", e); mPrivacyTxt = "Visit " + PRIVACY_WEB_URL; Linkify.addLinks(mPrivacyBodyView, Linkify.ALL); } } return null; } @Override protected void onPostExecute(Void result) { mEulaBodyView.setText(mEulaTxt); mPrivacyBodyView.setText(mPrivacyTxt); mEulaScroll.setVisibility(View.VISIBLE); mLoading.setVisibility(View.GONE); } } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); dialog.setContentView(R.layout.eula); //load the tabs mTabs = (TabHost)dialog.findViewById(android.R.id.tabhost); mTabs.setup(); TabSpec tab_one = mTabs.newTabSpec("eula_tab"); tab_one.setContent(R.id.eula_body); tab_one.setIndicator("EULA"); mTabs.addTab(tab_one); TabSpec tab_two = mTabs.newTabSpec("privacy_tab"); tab_two.setContent(R.id.priv_body); tab_two.setIndicator("Privacy Policy"); mTabs.addTab(tab_two); //work around lack of ability to control tab height from xml completely TabWidget tab_widget = (TabWidget)dialog.findViewById(android.R.id.tabs); mTabs.getTabWidget().getChildAt(0).getLayoutParams().height = tab_widget.getLayoutParams().height; mTabs.getTabWidget().getChildAt(1).getLayoutParams().height = tab_widget.getLayoutParams().height; //load the agreements mEulaScroll = (ScrollView)dialog.findViewById(R.id.eula_scroll); mLoading = (LinearLayout)dialog.findViewById(R.id.loading); mEulaBodyView = (TextView)dialog.findViewById(R.id.eula_body); mPrivacyBodyView = (TextView)dialog.findViewById(R.id.priv_body); mAcceptedCheckbox = (CheckBox)dialog.findViewById(R.id.eula_checkbox); mAcceptButton = (Button)dialog.findViewById(R.id.eula_accept); mRejectButton = (Button)dialog.findViewById(R.id.eula_reject); mEmailButton = (Button)dialog.findViewById(R.id.eula_email); mDismissButton = (Button)dialog.findViewById(R.id.eula_dismiss); mEulaAcceptArea = (LinearLayout)dialog.findViewById(R.id.eula_accept_area); mAcceptedCheckbox.setOnCheckedChangeListener(new OnAcceptToggle()); mAcceptButton.setOnClickListener(new OnAccept()); mRejectButton.setOnClickListener(new OnReject()); mEmailButton.setOnClickListener(new OnEmail()); mDismissButton.setOnClickListener(new OnDismiss()); if(!mRequired) { mEulaAcceptArea.setVisibility(View.GONE); mAcceptButton.setVisibility(View.GONE); mRejectButton.setVisibility(View.GONE); mDismissButton.setVisibility(View.VISIBLE); } else { mEulaAcceptArea.setVisibility(View.VISIBLE); mAcceptButton.setVisibility(View.VISIBLE); mRejectButton.setVisibility(View.VISIBLE); mDismissButton.setVisibility(View.GONE); } mAcceptButton.setEnabled(mAcceptedCheckbox.isChecked()); dialog.setTitle("Musubi Usage Agreements"); dialog.setOnKeyListener(new OnKey()); new AgreementLoader().execute(); return dialog; } class OnAcceptToggle implements OnCheckedChangeListener { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mAcceptButton.setEnabled(isChecked); } } class OnAccept implements OnClickListener { @Override public void onClick(View v) { if(!mAcceptedCheckbox.isChecked()) { return; } App.getUsageMetrics(mActivity).report(MusubiMetrics.EULA_ACCEPTED); mAccepted = true; broadcastResult(); dismiss(); } } class OnReject implements OnClickListener { @Override public void onClick(View v) { App.getUsageMetrics(mActivity).report(MusubiMetrics.EULA_DECLINED); broadcastResult(); dismiss(); } } class OnDismiss implements OnClickListener { @Override public void onClick(View v) { dismiss(); } } class OnEmail implements OnClickListener { @Override public void onClick(View v) { App.getUsageMetrics(mActivity).report(MusubiMetrics.EULA_EMAIL_REQUESTED); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(android.content.Intent.EXTRA_SUBJECT, EULA_MAIL_SUBJECT); intent.putExtra(android.content.Intent.EXTRA_TEXT, mEulaTxt + "\n\n\n\n\n" + mPrivacyTxt); startActivity(Intent.createChooser(intent, "Send Agreements...")); } } public class OnKey implements OnKeyListener { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { //disable back if (mRequired && keyCode == KeyEvent.KEYCODE_BACK) { return true; } return false; } } //closing one eula should close them all private static HashSet<Callback> sCallbacks = new HashSet<Callback>(); public void addCallback(Callback callback) { sCallbacks.add(callback); } public void broadcastResult() { for(Callback c : sCallbacks) { c.eulaResult(mAccepted); } sCallbacks.clear(); } }