diff --git a/apps/sasquatch/src/jcenterDependency/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java b/apps/sasquatch/src/jcenterDependency/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java new file mode 100644 index 0000000000..97af8d922b --- /dev/null +++ b/apps/sasquatch/src/jcenterDependency/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java @@ -0,0 +1,206 @@ +package com.microsoft.appcenter.sasquatch.activities; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.Spinner; +import android.widget.TextView; + +import com.microsoft.appcenter.AppCenter; +import com.microsoft.appcenter.analytics.Analytics; +import com.microsoft.appcenter.analytics.AnalyticsTransmissionTarget; +import com.microsoft.appcenter.sasquatch.R; +import com.microsoft.appcenter.sasquatch.util.EventActivityUtil; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +// TODO remove once new APIs available in jCenter. +public class EventActivity extends AppCompatActivity { + + private ViewGroup mList; + + private LayoutInflater mLayoutInflater; + + private Spinner mTransmissionTargetSpinner; + + private CheckBox mTransmissionEnabledCheckBox; + + private CheckBox mDeviceIdEnabledCheckBox; + + private Button mConfigureTargetPropertiesButton; + + private Button mOverrideCommonSchemaButton; + + private Button mPauseTransmissionButton; + + private Button mResumeTransmissionButton; + + private List mTransmissionTargets = new ArrayList<>(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_event); + mLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + /* Property view init. */ + mList = findViewById(R.id.list); + addProperty(); + + /* Test start from library. */ + AppCenter.startFromLibrary(this, Analytics.class); + + /* Transmission target views init. */ + mTransmissionTargetSpinner = findViewById(R.id.transmission_target); + ArrayAdapter targetAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, getResources().getStringArray(R.array.target_id_names)); + mTransmissionTargetSpinner.setAdapter(targetAdapter); + mTransmissionTargetSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateButtonStates(getSelectedTarget()); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + + /* Init Configure target properties button. */ + mConfigureTargetPropertiesButton = findViewById(R.id.configure_button); + mConfigureTargetPropertiesButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Intent intent = new Intent(EventActivity.this, EventPropertiesActivity.class); + intent.putExtra(ActivityConstants.EXTRA_TARGET_SELECTED, mTransmissionTargetSpinner.getSelectedItemPosition() - 1); + startActivity(intent); + } + }); + + /* Init enabled check boxes. */ + mTransmissionEnabledCheckBox = findViewById(R.id.transmission_enabled); + mDeviceIdEnabledCheckBox = findViewById(R.id.device_id_enabled); + mDeviceIdEnabledCheckBox.setVisibility(View.GONE); + + /* + * The first element is a placeholder for default transmission. + * The second one is the parent transmission target, the third one is a child, + * the forth is a grandchild, etc... + */ + mTransmissionTargets = EventActivityUtil.getAnalyticTransmissionTargetList(this); + + /* Init common schema properties button. */ + mOverrideCommonSchemaButton = findViewById(R.id.override_cs_button); + + /* Init override common schema properties button. */ + mOverrideCommonSchemaButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Intent intent = new Intent(EventActivity.this, CommonSchemaPropertiesActivity.class); + intent.putExtra(ActivityConstants.EXTRA_TARGET_SELECTED, mTransmissionTargetSpinner.getSelectedItemPosition()); + startActivity(intent); + } + }); + + /* Init pause/resume buttons. */ + mPauseTransmissionButton = findViewById(R.id.pause_transmission_button); + mPauseTransmissionButton.setVisibility(View.GONE); + mResumeTransmissionButton = findViewById(R.id.resume_transmission_button); + mResumeTransmissionButton.setVisibility(View.GONE); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.add, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_add: + addProperty(); + break; + } + return true; + } + + private void addProperty() { + mList.addView(mLayoutInflater.inflate(R.layout.property, mList, false)); + } + + @SuppressWarnings("unused") + public void send(@SuppressWarnings("UnusedParameters") View view) { + String name = ((TextView) findViewById(R.id.name)).getText().toString(); + Map properties = null; + for (int i = 0; i < mList.getChildCount(); i++) { + View childAt = mList.getChildAt(i); + CharSequence key = ((TextView) childAt.findViewById(R.id.key)).getText(); + CharSequence value = ((TextView) childAt.findViewById(R.id.value)).getText(); + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + if (properties == null) { + properties = new HashMap<>(); + } + properties.put(key.toString(), value.toString()); + } + } + + /* First item is always empty as it's default value which means either appcenter, one collector or both. */ + AnalyticsTransmissionTarget target = getSelectedTarget(); + if (target == null) { + Analytics.trackEvent(name, properties); + } else { + target.trackEvent(name, properties); + } + } + + private AnalyticsTransmissionTarget getSelectedTarget() { + return mTransmissionTargets.get(mTransmissionTargetSpinner.getSelectedItemPosition()); + } + + public void toggleTransmissionEnabled(View view) { + boolean checked = mTransmissionEnabledCheckBox.isChecked(); + final AnalyticsTransmissionTarget target = getSelectedTarget(); + if (target != null) { + target.setEnabledAsync(checked); + updateButtonStates(target); + } + } + + public void toggleDeviceIdEnabled(View view) { + } + + private void updateButtonStates(AnalyticsTransmissionTarget target) { + if (target == null) { + mTransmissionEnabledCheckBox.setVisibility(View.GONE); + mConfigureTargetPropertiesButton.setVisibility(View.GONE); + mOverrideCommonSchemaButton.setVisibility(View.GONE); + mDeviceIdEnabledCheckBox.setVisibility(View.GONE); + mPauseTransmissionButton.setVisibility(View.GONE); + mResumeTransmissionButton.setVisibility(View.GONE); + } else { + mTransmissionEnabledCheckBox.setVisibility(View.VISIBLE); + mConfigureTargetPropertiesButton.setVisibility(View.VISIBLE); + mOverrideCommonSchemaButton.setVisibility(View.VISIBLE); + boolean enabled = target.isEnabledAsync().get(); + mTransmissionEnabledCheckBox.setChecked(enabled); + mTransmissionEnabledCheckBox.setText(enabled ? R.string.transmission_enabled : R.string.transmission_disabled); + } + } +} diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/CustomPropertiesActivity.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/CustomPropertiesActivity.java index d2854384ce..128b0eab05 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/CustomPropertiesActivity.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/CustomPropertiesActivity.java @@ -1,42 +1,24 @@ package com.microsoft.appcenter.sasquatch.activities; -import android.app.DatePickerDialog; -import android.app.Dialog; -import android.app.TimePickerDialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.CheckBox; -import android.widget.DatePicker; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TimePicker; import com.microsoft.appcenter.AppCenter; import com.microsoft.appcenter.CustomProperties; import com.microsoft.appcenter.sasquatch.R; +import com.microsoft.appcenter.sasquatch.fragments.CustomPropertyFragment; -import java.text.DateFormat; import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; import java.util.List; public class CustomPropertiesActivity extends AppCompatActivity { private final List mProperties = new ArrayList<>(); - private CustomPropertyFragment mCurrentProperty = null; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -75,187 +57,4 @@ public void send(@SuppressWarnings("UnusedParameters") View view) { } AppCenter.setCustomProperties(customProperties); } - - public static class CustomPropertyFragment extends Fragment - implements DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener { - - private static final int TYPE_CLEAR = 0; - private static final int TYPE_BOOLEAN = 1; - private static final int TYPE_NUMBER = 2; - private static final int TYPE_DATETIME = 3; - private static final int TYPE_STRING = 4; - - private EditText mEditKey; - private Spinner mEditType; - private EditText mEditString; - private EditText mEditNumber; - private EditText mEditDate; - private EditText mEditTime; - private CheckBox mEditBool; - private View mDateTime; - - private Date mDate; - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.custom_property, container, false); - - mEditKey = view.findViewById(R.id.key); - mEditType = view.findViewById(R.id.type); - mEditString = view.findViewById(R.id.string); - mEditNumber = view.findViewById(R.id.number); - mEditDate = view.findViewById(R.id.date); - mEditTime = view.findViewById(R.id.time); - mEditBool = view.findViewById(R.id.bool); - mDateTime = view.findViewById(R.id.datetime); - - mEditType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - updateValueType(); - } - - @Override - public void onNothingSelected(AdapterView parent) { - } - }); - mEditDate.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View view) { - showDate(); - } - }); - mEditTime.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View view) { - showTime(); - } - }); - - setDate(new Date()); - - return view; - } - - private void showDate() { - CustomPropertiesActivity activity = (CustomPropertiesActivity) getActivity(); - - //noinspection ConstantConditions - activity.mCurrentProperty = this; - new DatePickerFragment().show(activity.getSupportFragmentManager(), "datePicker"); - } - - private void showTime() { - CustomPropertiesActivity activity = (CustomPropertiesActivity) getActivity(); - - //noinspection ConstantConditions - activity.mCurrentProperty = this; - new TimePickerFragment().show(activity.getSupportFragmentManager(), "timePicker"); - } - - private void updateValueType() { - int type = mEditType.getSelectedItemPosition(); - mEditString.setVisibility(type == TYPE_STRING ? View.VISIBLE : View.GONE); - mEditNumber.setVisibility(type == TYPE_NUMBER ? View.VISIBLE : View.GONE); - mEditBool.setVisibility(type == TYPE_BOOLEAN ? View.VISIBLE : View.GONE); - mDateTime.setVisibility(type == TYPE_DATETIME ? View.VISIBLE : View.GONE); - } - - private void setDate(Date date) { - mDate = date; - mEditDate.setText(DateFormat.getDateInstance().format(mDate)); - mEditTime.setText(DateFormat.getTimeInstance().format(mDate)); - } - - public void onDateSet(DatePicker view, int year, int month, int day) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(mDate); - calendar.set(Calendar.YEAR, year); - calendar.set(Calendar.MONTH, month); - calendar.set(Calendar.DAY_OF_MONTH, day); - setDate(calendar.getTime()); - } - - public void onTimeSet(TimePicker view, int hourOfDay, int minute) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(mDate); - calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); - calendar.set(Calendar.MINUTE, minute); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - setDate(calendar.getTime()); - } - - void set(CustomProperties customProperties) { - int type = mEditType.getSelectedItemPosition(); - String key = mEditKey.getText().toString(); - switch (type) { - case TYPE_CLEAR: - customProperties.clear(key); - break; - case TYPE_BOOLEAN: - customProperties.set(key, mEditBool.isChecked()); - break; - case TYPE_NUMBER: - String stringValue = mEditNumber.getText().toString(); - Number value; - try { - value = Integer.parseInt(stringValue); - } catch (NumberFormatException ignored) { - value = Double.parseDouble(stringValue); - } - customProperties.set(key, value); - break; - case TYPE_DATETIME: - customProperties.set(key, mDate); - break; - case TYPE_STRING: - customProperties.set(key, mEditString.getText().toString()); - break; - } - } - } - - public static class DatePickerFragment extends DialogFragment { - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - CustomPropertiesActivity activity = (CustomPropertiesActivity) getActivity(); - - @SuppressWarnings("ConstantConditions") - CustomPropertyFragment property = activity.mCurrentProperty; - Calendar calendar = Calendar.getInstance(); - if (property != null) { - calendar.setTime(property.mDate); - } - int year = calendar.get(Calendar.YEAR); - int month = calendar.get(Calendar.MONTH); - int day = calendar.get(Calendar.DAY_OF_MONTH); - return new DatePickerDialog(activity, property, year, month, day); - } - } - - public static class TimePickerFragment extends DialogFragment { - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - CustomPropertiesActivity activity = (CustomPropertiesActivity) getActivity(); - - @SuppressWarnings("ConstantConditions") - CustomPropertyFragment property = activity.mCurrentProperty; - Calendar calendar = Calendar.getInstance(); - if (property != null) { - calendar.setTime(property.mDate); - } - int hour = calendar.get(Calendar.HOUR_OF_DAY); - int minute = calendar.get(Calendar.MINUTE); - return new TimePickerDialog(activity, property, hour, minute, true); - } - } } diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/LogActivity.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/LogActivity.java deleted file mode 100644 index 8791b52562..0000000000 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/LogActivity.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.microsoft.appcenter.sasquatch.activities; - -import android.content.Context; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.microsoft.appcenter.sasquatch.R; - -import java.util.HashMap; -import java.util.Map; - -public abstract class LogActivity extends AppCompatActivity { - - private ViewGroup mList; - - private LayoutInflater mLayoutInflater; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(getLayoutId()); - mLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - /* Property view init. */ - mList = findViewById(R.id.list); - addProperty(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.add, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_add: - addProperty(); - break; - } - return true; - } - - private void addProperty() { - mList.addView(mLayoutInflater.inflate(R.layout.property, mList, false)); - } - - @SuppressWarnings("unused") - public void send(@SuppressWarnings("UnusedParameters") View view) { - String name = ((TextView) findViewById(R.id.name)).getText().toString(); - Map properties = null; - for (int i = 0; i < mList.getChildCount(); i++) { - View childAt = mList.getChildAt(i); - CharSequence key = ((TextView) childAt.findViewById(R.id.key)).getText(); - CharSequence value = ((TextView) childAt.findViewById(R.id.value)).getText(); - if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { - if (properties == null) { - properties = new HashMap<>(); - } - properties.put(key.toString(), value.toString()); - } - } - trackLog(name, properties); - } - - abstract void trackLog(String name, Map properties); - - abstract int getLayoutId(); -} diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/PageActivity.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/PageActivity.java index 5d4e77856f..d4754efa4f 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/PageActivity.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/PageActivity.java @@ -1,19 +1,74 @@ package com.microsoft.appcenter.sasquatch.activities; +import android.content.Context; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + import com.microsoft.appcenter.analytics.AnalyticsPrivateHelper; import com.microsoft.appcenter.sasquatch.R; +import java.util.HashMap; import java.util.Map; -public class PageActivity extends LogActivity { +public class PageActivity extends AppCompatActivity { + + private ViewGroup mList; + + private LayoutInflater mLayoutInflater; @Override - int getLayoutId() { - return R.layout.activity_page; + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_page); + mLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + /* Property view init. */ + mList = findViewById(R.id.list); + addProperty(); } @Override - void trackLog(String name, Map properties) { + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.add, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_add: + addProperty(); + break; + } + return true; + } + + private void addProperty() { + mList.addView(mLayoutInflater.inflate(R.layout.property, mList, false)); + } + + @SuppressWarnings("unused") + public void send(@SuppressWarnings("UnusedParameters") View view) { + String name = ((TextView) findViewById(R.id.name)).getText().toString(); + Map properties = null; + for (int i = 0; i < mList.getChildCount(); i++) { + View childAt = mList.getChildAt(i); + CharSequence key = ((TextView) childAt.findViewById(R.id.key)).getText(); + CharSequence value = ((TextView) childAt.findViewById(R.id.value)).getText(); + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + if (properties == null) { + properties = new HashMap<>(); + } + properties.put(key.toString(), value.toString()); + } + } AnalyticsPrivateHelper.trackPage(name, properties); } } diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/CustomPropertyFragment.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/CustomPropertyFragment.java new file mode 100644 index 0000000000..bd8e5f70b0 --- /dev/null +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/CustomPropertyFragment.java @@ -0,0 +1,96 @@ +package com.microsoft.appcenter.sasquatch.fragments; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.Spinner; + +import com.microsoft.appcenter.CustomProperties; +import com.microsoft.appcenter.sasquatch.R; + +public class CustomPropertyFragment extends EditDateTimeFragment { + + public static final int TYPE_CLEAR = 0; + public static final int TYPE_BOOLEAN = 1; + public static final int TYPE_NUMBER = 2; + public static final int TYPE_DATETIME = 3; + public static final int TYPE_STRING = 4; + + private EditText mEditKey; + private Spinner mEditType; + private EditText mEditString; + private EditText mEditNumber; + private CheckBox mEditBool; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.custom_property, container, false); + + mEditKey = view.findViewById(R.id.key); + mEditType = view.findViewById(R.id.type); + mEditString = view.findViewById(R.id.string); + mEditNumber = view.findViewById(R.id.number); + mEditBool = view.findViewById(R.id.bool); + + mEditType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateValueType(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + + return view; + } + + private void updateValueType() { + int type = getType(); + mEditString.setVisibility(type == TYPE_STRING ? View.VISIBLE : View.GONE); + mEditNumber.setVisibility(type == TYPE_NUMBER ? View.VISIBLE : View.GONE); + mEditBool.setVisibility(type == TYPE_BOOLEAN ? View.VISIBLE : View.GONE); + mDateTime.setVisibility(type == TYPE_DATETIME ? View.VISIBLE : View.GONE); + } + + public int getType() { + return mEditType.getSelectedItemPosition(); + } + + public void set(CustomProperties customProperties) { + int type = getType(); + String key = mEditKey.getText().toString(); + switch (type) { + case TYPE_CLEAR: + customProperties.clear(key); + break; + case TYPE_BOOLEAN: + customProperties.set(key, mEditBool.isChecked()); + break; + case TYPE_NUMBER: + String stringValue = mEditNumber.getText().toString(); + Number value; + try { + value = Integer.parseInt(stringValue); + } catch (NumberFormatException ignored) { + value = Double.parseDouble(stringValue); + } + customProperties.set(key, value); + break; + case TYPE_DATETIME: + customProperties.set(key, mDate); + break; + case TYPE_STRING: + customProperties.set(key, mEditString.getText().toString()); + break; + } + } +} \ No newline at end of file diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/DatePickerFragment.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/DatePickerFragment.java new file mode 100644 index 0000000000..e1d0080295 --- /dev/null +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/DatePickerFragment.java @@ -0,0 +1,41 @@ +package com.microsoft.appcenter.sasquatch.fragments; + +import android.app.DatePickerDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; + +import java.util.Calendar; +import java.util.Date; + +public class DatePickerFragment extends DialogFragment { + + public static final String INITIAL_DATE = "initial_date"; + + private DatePickerDialog.OnDateSetListener mListener; + + public Date getInitialDate() { + Bundle arguments = getArguments(); + if (arguments != null) { + return (Date) arguments.getSerializable(INITIAL_DATE); + } + return null; + } + + public void setListener(DatePickerDialog.OnDateSetListener listener) { + mListener = listener; + } + + @SuppressWarnings("ConstantConditions") + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(getInitialDate()); + int year = calendar.get(Calendar.YEAR); + int month = calendar.get(Calendar.MONTH); + int day = calendar.get(Calendar.DAY_OF_MONTH); + return new DatePickerDialog(getActivity(), mListener, year, month, day); + } +} diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/EditDateTimeFragment.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/EditDateTimeFragment.java new file mode 100644 index 0000000000..5bfc18e61f --- /dev/null +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/EditDateTimeFragment.java @@ -0,0 +1,103 @@ +package com.microsoft.appcenter.sasquatch.fragments; + +import android.app.DatePickerDialog; +import android.app.TimePickerDialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.view.View; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.TimePicker; + +import com.microsoft.appcenter.sasquatch.R; + +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; + +public abstract class EditDateTimeFragment extends Fragment + implements DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener { + + private EditText mEditDate; + private EditText mEditTime; + protected View mDateTime; + + protected Date mDate; + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + mEditDate = view.findViewById(R.id.date); + mEditTime = view.findViewById(R.id.time); + mDateTime = view.findViewById(R.id.datetime); + + mEditDate.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View view) { + showDate(); + } + }); + mEditTime.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View view) { + showTime(); + } + }); + + setDate(new Date()); + } + + private void showDate() { + FragmentActivity activity = getActivity(); + if (activity == null) { + return; + } + Bundle bundle = new Bundle(); + bundle.putSerializable(DatePickerFragment.INITIAL_DATE, mDate); + DatePickerFragment fragment = new DatePickerFragment(); + fragment.setArguments(bundle); + fragment.setListener(this); + fragment.show(activity.getSupportFragmentManager(), "datePicker"); + } + + private void showTime() { + FragmentActivity activity = getActivity(); + if (activity == null) { + return; + } + Bundle bundle = new Bundle(); + bundle.putSerializable(TimePickerFragment.INITIAL_TIME, mDate); + TimePickerFragment fragment = new TimePickerFragment(); + fragment.setArguments(bundle); + fragment.setListener(this); + fragment.show(getActivity().getSupportFragmentManager(), "timePicker"); + } + + private void setDate(Date date) { + mDate = date; + mEditDate.setText(DateFormat.getDateInstance().format(mDate)); + mEditTime.setText(DateFormat.getTimeInstance().format(mDate)); + } + + public void onDateSet(DatePicker view, int year, int month, int day) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(mDate); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month); + calendar.set(Calendar.DAY_OF_MONTH, day); + setDate(calendar.getTime()); + } + + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(mDate); + calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + setDate(calendar.getTime()); + } +} \ No newline at end of file diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/TimePickerFragment.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/TimePickerFragment.java new file mode 100644 index 0000000000..43dd2a9025 --- /dev/null +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/fragments/TimePickerFragment.java @@ -0,0 +1,39 @@ +package com.microsoft.appcenter.sasquatch.fragments; + +import android.app.Dialog; +import android.app.TimePickerDialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; + +import java.util.Calendar; +import java.util.Date; + +public class TimePickerFragment extends DialogFragment { + + public static final String INITIAL_TIME = "initial_time"; + + private TimePickerDialog.OnTimeSetListener mListener; + + public Date getInitialTime() { + Bundle arguments = getArguments(); + if (arguments != null) { + return (Date) arguments.getSerializable(INITIAL_TIME); + } + return null; + } + + public void setListener(TimePickerDialog.OnTimeSetListener listener) { + mListener = listener; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(getInitialTime()); + int hour = calendar.get(Calendar.HOUR_OF_DAY); + int minute = calendar.get(Calendar.MINUTE); + return new TimePickerDialog(getActivity(), mListener, hour, minute, true); + } +} diff --git a/apps/sasquatch/src/main/res/layout/typed_property.xml b/apps/sasquatch/src/main/res/layout/typed_property.xml new file mode 100644 index 0000000000..d268c7bf2f --- /dev/null +++ b/apps/sasquatch/src/main/res/layout/typed_property.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/sasquatch/src/main/res/values/strings.xml b/apps/sasquatch/src/main/res/values/strings.xml index 4a12fc364f..583ed175c9 100644 --- a/apps/sasquatch/src/main/res/values/strings.xml +++ b/apps/sasquatch/src/main/res/values/strings.xml @@ -29,6 +29,13 @@ Key Value Type + + Boolean + Double + Long + Date/Time + String + Clear Boolean diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java b/apps/sasquatch/src/projectDependency/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java similarity index 72% rename from apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java rename to apps/sasquatch/src/projectDependency/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java index 5d59576cba..3a427e8066 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java +++ b/apps/sasquatch/src/projectDependency/java/com/microsoft/appcenter/sasquatch/activities/EventActivity.java @@ -2,29 +2,35 @@ import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.Spinner; +import android.widget.TextView; import com.microsoft.appcenter.AppCenter; import com.microsoft.appcenter.analytics.Analytics; import com.microsoft.appcenter.analytics.AnalyticsTransmissionTarget; -import com.microsoft.appcenter.analytics.PropertyConfigurator; +import com.microsoft.appcenter.analytics.EventProperties; import com.microsoft.appcenter.sasquatch.R; +import com.microsoft.appcenter.sasquatch.fragments.TypedPropertyFragment; import com.microsoft.appcenter.sasquatch.util.EventActivityUtil; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -public class EventActivity extends LogActivity { +// TODO move to main folder once new APIs available in jCenter +public class EventActivity extends AppCompatActivity { /** * Remember for what targets the device id was enabled. @@ -48,18 +54,12 @@ public class EventActivity extends LogActivity { private List mTransmissionTargets = new ArrayList<>(); - // TODO remove reflection once new APIs available in jCenter. - private Method mCollectDeviceIdMethod; - - // TODO remove reflection once new APIs available in jCenter. - private Method mPauseMethod; - - // TODO remove reflection once new APIs available in jCenter. - private Method mResumeMethod; + private final List mProperties = new ArrayList<>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.activity_event); /* Test start from library. */ AppCenter.startFromLibrary(this, Analytics.class); @@ -95,12 +95,6 @@ public void onClick(View v) { /* Init enabled check boxes. */ mTransmissionEnabledCheckBox = findViewById(R.id.transmission_enabled); mDeviceIdEnabledCheckBox = findViewById(R.id.device_id_enabled); - try { - //noinspection JavaReflectionMemberAccess - mCollectDeviceIdMethod = PropertyConfigurator.class.getMethod("collectDeviceId"); - } catch (NoSuchMethodException e) { - mDeviceIdEnabledCheckBox.setVisibility(View.GONE); - } /* * The first element is a placeholder for default transmission. @@ -123,59 +117,89 @@ public void onClick(View v) { } }); - /* Init pause/resume buttons. TODO remove reflection once SDKs are released. */ + /* Init pause/resume buttons. */ mPauseTransmissionButton = findViewById(R.id.pause_transmission_button); - try { - //noinspection JavaReflectionMemberAccess - mPauseMethod = AnalyticsTransmissionTarget.class.getMethod("pause"); - } catch (NoSuchMethodException e) { - mPauseTransmissionButton.setVisibility(View.GONE); - } mPauseTransmissionButton.setOnClickListener(new View.OnClickListener() { @Override @SuppressWarnings("ConstantConditions") public void onClick(View v) { - try { - mPauseMethod.invoke(getSelectedTarget()); - } catch (IllegalAccessException ignored) { - } catch (InvocationTargetException ignored) { - } + getSelectedTarget().pause(); } }); mResumeTransmissionButton = findViewById(R.id.resume_transmission_button); - try { - //noinspection JavaReflectionMemberAccess - mResumeMethod = AnalyticsTransmissionTarget.class.getMethod("resume"); - } catch (NoSuchMethodException e) { - mResumeTransmissionButton.setVisibility(View.GONE); - } mResumeTransmissionButton.setOnClickListener(new View.OnClickListener() { @Override @SuppressWarnings("ConstantConditions") public void onClick(View v) { - try { - mResumeMethod.invoke(getSelectedTarget()); - } catch (IllegalAccessException ignored) { - } catch (InvocationTargetException ignored) { - } + getSelectedTarget().resume(); } }); } + @Override - int getLayoutId() { - return R.layout.activity_event; + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.add, menu); + return true; } @Override - void trackLog(String name, Map properties) { + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_add: + addProperty(); + break; + } + return true; + } + + private void addProperty() { + TypedPropertyFragment fragment = new TypedPropertyFragment(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.list, fragment).commit(); + mProperties.add(fragment); + } + + private boolean onlyStringProperties() { + for (TypedPropertyFragment fragment : mProperties) { + if (fragment.getType() != TypedPropertyFragment.TYPE_STRING) { + return false; + } + } + return true; + } + + @SuppressWarnings("unused") + public void send(@SuppressWarnings("UnusedParameters") View view) { + String name = ((TextView) findViewById(R.id.name)).getText().toString(); + Map properties = null; + EventProperties typedProperties = null; + if (mProperties.size() > 0) { + if (onlyStringProperties()) { + properties = new HashMap<>(); + for (TypedPropertyFragment fragment : mProperties) { + fragment.set(properties); + } + } else { + typedProperties = new EventProperties(); + for (TypedPropertyFragment fragment : mProperties) { + fragment.set(typedProperties); + } + } + } /* First item is always empty as it's default value which means either appcenter, one collector or both. */ AnalyticsTransmissionTarget target = getSelectedTarget(); if (target == null) { - Analytics.trackEvent(name, properties); + if (typedProperties != null) { + Analytics.trackEvent(name, typedProperties); + } else if (properties != null) { + Analytics.trackEvent(name, properties); + } else { + Analytics.trackEvent(name); + } } else { target.trackEvent(name, properties); } @@ -198,14 +222,7 @@ public void toggleDeviceIdEnabled(View view) { final AnalyticsTransmissionTarget target = getSelectedTarget(); if (target != null) { updateButtonStates(target); - - // TODO remove reflection once new APIs available in jCenter. - // target.getPropertyConfigurator().collectDeviceId(); - try { - mCollectDeviceIdMethod.invoke(target.getPropertyConfigurator()); - } catch (IllegalAccessException ignored) { - } catch (InvocationTargetException ignored) { - } + target.getPropertyConfigurator().collectDeviceId(); mDeviceIdEnabledCheckBox.setChecked(true); mDeviceIdEnabledCheckBox.setText(R.string.device_id_enabled); mDeviceIdEnabledCheckBox.setEnabled(false); @@ -225,19 +242,13 @@ private void updateButtonStates(AnalyticsTransmissionTarget target) { mTransmissionEnabledCheckBox.setVisibility(View.VISIBLE); mConfigureTargetPropertiesButton.setVisibility(View.VISIBLE); mOverrideCommonSchemaButton.setVisibility(View.VISIBLE); - if (mPauseMethod != null) { - mPauseTransmissionButton.setVisibility(View.VISIBLE); - } - if (mResumeMethod != null) { - mResumeTransmissionButton.setVisibility(View.VISIBLE); - } + mPauseTransmissionButton.setVisibility(View.VISIBLE); + mResumeTransmissionButton.setVisibility(View.VISIBLE); boolean enabled = target.isEnabledAsync().get(); mTransmissionEnabledCheckBox.setChecked(enabled); mTransmissionEnabledCheckBox.setText(enabled ? R.string.transmission_enabled : R.string.transmission_disabled); boolean deviceIdEnabled = DEVICE_ID_ENABLED.contains(target); - if (mCollectDeviceIdMethod != null) { - mDeviceIdEnabledCheckBox.setVisibility(View.VISIBLE); - } + mDeviceIdEnabledCheckBox.setVisibility(View.VISIBLE); mDeviceIdEnabledCheckBox.setChecked(deviceIdEnabled); mDeviceIdEnabledCheckBox.setText(deviceIdEnabled ? R.string.device_id_enabled : R.string.device_id_disabled); mDeviceIdEnabledCheckBox.setEnabled(!deviceIdEnabled); diff --git a/apps/sasquatch/src/projectDependency/java/com/microsoft/appcenter/sasquatch/fragments/TypedPropertyFragment.java b/apps/sasquatch/src/projectDependency/java/com/microsoft/appcenter/sasquatch/fragments/TypedPropertyFragment.java new file mode 100644 index 0000000000..9b66e6a8d3 --- /dev/null +++ b/apps/sasquatch/src/projectDependency/java/com/microsoft/appcenter/sasquatch/fragments/TypedPropertyFragment.java @@ -0,0 +1,111 @@ +package com.microsoft.appcenter.sasquatch.fragments; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.Spinner; + +import com.microsoft.appcenter.analytics.EventProperties; +import com.microsoft.appcenter.sasquatch.R; + +import java.util.Map; + +// TODO move to main folder once new APIs available in jCenter +public class TypedPropertyFragment extends EditDateTimeFragment { + + public static final int TYPE_BOOLEAN = 0; + public static final int TYPE_NUMBER_DOUBLE = 1; + public static final int TYPE_NUMBER_LONG = 2; + public static final int TYPE_DATETIME = 3; + public static final int TYPE_STRING = 4; + + private EditText mEditKey; + private Spinner mEditType; + private EditText mEditString; + private EditText mEditNumberDouble; + private EditText mEditNumberLong; + private CheckBox mEditBool; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.typed_property, container, false); + + mEditKey = view.findViewById(R.id.key); + mEditType = view.findViewById(R.id.type); + mEditString = view.findViewById(R.id.string); + mEditNumberDouble = view.findViewById(R.id.number_double); + mEditNumberLong = view.findViewById(R.id.number_long); + mEditBool = view.findViewById(R.id.bool); + + mEditType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateValueType(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + + return view; + } + + private void updateValueType() { + int type = getType(); + mEditString.setVisibility(type == TYPE_STRING ? View.VISIBLE : View.GONE); + mEditBool.setVisibility(type == TYPE_BOOLEAN ? View.VISIBLE : View.GONE); + mEditNumberDouble.setVisibility(type == TYPE_NUMBER_DOUBLE ? View.VISIBLE : View.GONE); + mEditNumberLong.setVisibility(type == TYPE_NUMBER_LONG ? View.VISIBLE : View.GONE); + mDateTime.setVisibility(type == TYPE_DATETIME ? View.VISIBLE : View.GONE); + } + + public int getType() { + return mEditType.getSelectedItemPosition(); + } + + public void set(Map eventProperties) { + int type = getType(); + String key = mEditKey.getText().toString(); + switch (type) { + case TYPE_STRING: + eventProperties.put(key, mEditString.getText().toString()); + break; + } + } + + public void set(EventProperties eventProperties) { + int type = getType(); + String key = mEditKey.getText().toString(); + switch (type) { + case TYPE_BOOLEAN: + eventProperties.set(key, mEditBool.isChecked()); + break; + case TYPE_NUMBER_DOUBLE: { + String stringValue = mEditNumberDouble.getText().toString(); + Double value = Double.parseDouble(stringValue); + eventProperties.set(key, value); + break; + } + case TYPE_NUMBER_LONG: { + String stringValue = mEditNumberLong.getText().toString(); + Long value = Long.parseLong(stringValue); + eventProperties.set(key, value); + break; + } + case TYPE_DATETIME: + eventProperties.set(key, mDate); + break; + case TYPE_STRING: + eventProperties.set(key, mEditString.getText().toString()); + break; + } + } +}